2012-05-31 9 views
40

Estoy tratando de usar el comando sed en un script de shell donde quiero eliminar líneas que dicen STARTremoveThisComment y líneas que dicen removeThisCommentEND.¿Cómo ejecuto el comando sed con entrada y salida como el mismo archivo?

soy capaz de hacerlo cuando lo copio a un nuevo archivo usando

sed 's/STARTremoveThisComment//' > test 

Pero, ¿cómo puedo hacer esto utilizando el mismo archivo como entrada y salida?

+1

sed -ES/some1/some2/g input.file> output.file; output.file mv input.file – 0xAX

Respuesta

72

sed -i (o la versión extendida, --in-place) automatizará el proceso normalmente se hace con menos implementaciones avanzadas, el de enviar la salida a un archivo temporal, a continuación, cambiar el nombre que volver a la original.

El -i es para la edición in situ, y también se puede proporcionar un sufijo de respaldo para mantener una copia del original:

sed -i.bak fileToChange 
sed --in-place=.bak fileToChange 

Tanto de los que mantendrá el archivo original en fileToChange.bak.

Tenga en cuenta que en el lugar de edición puede no estar disponible en todas las implementaciones sed pero es en GNU sed que debería estar disponible en todas las variantes de Linux, según sus etiquetas.

Si está utilizando una aplicación más primitivo, puede utilizar algo como:

sed 'whatever' oldfile >newfile ; mv newfile oldfile 

aunque un poco más de la comprobación de errores no estaría mal.

+1

funcionó como un encanto! :) esto es lo que utilicé: 'sed -i 's/STARTremoveThisComment //' test' –

+1

Tenga en cuenta que' --in-place' es un gnuismo y no funcionará en todas las versiones de sed. Si espera usar su script sed en máquinas que no son Linux, no puede usarlo. –

+0

@william, pensé en eso, pero no me preocupé mucho porque la pregunta tenía una etiqueta de Linux. Lo aclararé – paxdiablo

0

Por lo que sé, no es posible usar el mismo archivo para entrada y salida. Aunque una solución es crear un script de shell que lo guarde en otro archivo, elimine la entrada anterior y cambie el nombre del resultado al nombre del archivo de entrada.

sed -e s/try/this/g input.file > output.file;mv output.file input.file 
+2

Por lo menos no debe esto ser 'sed. .. & mv ... '¿entonces una falla sed no sobrescribirá su entrada con un archivo en blanco? –

5

No deberías usar sed para eso. Esta pregunta parece surgir ridículamente a menudo, y parece muy extraño que sí, ya que la solución general es tan trivial, parece extraño que la gente quiera saber cómo hacerlo en sed, y en python, y en ruby, etc. . Si usted quiere tener un filtro de operar en una entrada y sobrescribir, utilice la siguiente secuencia de comandos simple:

#!/bin/sh -e 
in=${1?No input file specified} 
mv $in ${bak=.$in.bak} 
shift 
"[email protected]" < $bak > $in 

poner esto en tu camino en un nombre de archivo ejecutable inline, y entonces el problema se resuelve en general. Por ejemplo:

inline input-file sed -e s/foo/bar/g 

Ahora, si quieres añadir lógica para mantener múltiples copias de seguridad, o si usted tiene algunas opciones para cambiar el esquema de denominación de copia de seguridad, o lo que sea, podría solucionar esto en un solo lugar. ¿Cuál es la opción de línea de comando para obtener contadores de 1 en el archivo de copia de seguridad cuando se procesa un archivo en el lugar con perl? ¿Qué tal con ruby? ¿La opción es diferente para gnu-sed? ¿Cómo lo maneja awk? Todo el maldito punto de Unix es que las herramientas hacen una sola cosa. La lógica de manejo para los archivos de respaldo es una segunda cosa y debe ser eliminada. Si está implementando una herramienta, no agregue lógica para crear archivos de respaldo. Dile a tus usuarios que utilicen una segunda herramienta para eso. La integración es mala. La modularidad es buena. Esa es la forma de Unix.

Observe que este script tiene varios problemas.Los permisos/modo del archivo de entrada pueden cambiarse, por ejemplo. Estoy seguro de que hay innumerables otros problemas. Sin embargo, al colocar la lógica de la copia de seguridad en una secuencia de comandos contenedora, localiza todos estos problemas y no tiene que preocuparse de que sed sobrescriba los archivos y cambie el modo, mientras que python mantiene el archivo en su lugar y no cambia el inode (lo hice esos dos casos, el punto es que no todas las herramientas a utilizar la misma lógica, mientras que el guión envoltorio lo hará.)

+0

Gracias, me gusta el guión y lo he adaptado a mi gusto #!/Bin/sh -e in = $ { 1? No se especificó ningún archivo de entrada} mv "$ in" $ {bak = in.bak} shift "$ @" < "$bak" > $ in && rm "$ bak" || mv "$ bak" "$ in" –

+2

No estoy de acuerdo, si 'sed' tiene una función para hacerlo, entonces no veo ninguna razón para no hacerlo. También parece ajustarse a lo que él quiere. – markzz

+0

@MarkWeiman El problema es que "sed" no tiene esa función. Una implementación particular de sed soporta esa función, y tan pronto como intenta mover su script a una máquina que usa una implementación diferente, la secuencia de comandos se rompe. –

5

Usted puede usar la bandera -i para la edición in situ y la -e para especificando la expresión de script normal:

sed -i -e 's/pattern_to_search/text_to_replace/' file.txt 

Para eliminar las líneas que coinciden con un patrón determinado que puede usar la sintaxis más simple. Note la d bandera:

sed -i '/pattern_to_search/d' file.txt 
+0

en mi mac esto también crea una copia del archivo original como archivo.txt-e, ¿por qué? – SuperUberDuper

+0

¿Estás dejando un espacio entre -i y -e? porque de lo contrario, considerará el -e como el SUFIJO para la copia de seguridad. La ayuda de Sed muestra la descripción de -i: '-i [SUFIJO], --in-place [= SUFFIX] edite los archivos en su lugar (hace copias de seguridad si se proporciona SUFIJO)' Acabo de probar esto otra vez en mi máquina Linux y funciona bien – Tiago

Cuestiones relacionadas