sed editar archivo en su lugar

Estoy tratando de averiguar si es posible editar un archivo en un único comando sed sin transferir manualmente el contenido editado a un nuevo archivo y luego cambiar el nombre del nuevo archivo al nombre original del archivo. -i opción -i pero mi sistema Solaris decía que -i es una opción ilegal. ¿Hay alguna otra manera?

La opción -i transmite el contenido editado a un nuevo archivo y luego lo renombra detrás de las escenas, de todos modos.

Ejemplo:

 sed -i 's/STRING_TO_REPLACE/STRING_TO_REPLACE_IT/g' filename 

y

 sed -i '' 's/STRING_TO_REPLACE/STRING_TO_REPLACE_IT/g' filename 

en macOS .

En un sistema donde sed no tiene la capacidad de editar archivos en su lugar, creo que la mejor solución sería usar perl :

 perl -pi -e 's/foo/bar/g' file.txt 

Aunque esto crea un archivo temporal, reemplaza el original porque se ha proporcionado un sufijo / extensión vacío en el lugar.

Tenga en cuenta que en OS X puede obtener errores extraños como “código de comando no válido” u otros errores extraños al ejecutar este comando. Para solucionar este problema, intenta

 sed -i '' -e "s/STRING_TO_REPLACE/STRING_TO_REPLACE_IT/g"  

Esto se debe a que en la versión OSX de sed , la opción -i espera un argumento de extension para que su comando se analice como el argumento de extension y la ruta del archivo se interprete como el código de comando. Fuente: https://stackoverflow.com/a/19457213

Lo siguiente funciona bien en mi mac

 sed -i.bak 's/foo/bar/g' sample 

Estamos reemplazando foo con barra en archivo de muestra. La copia de seguridad del archivo original se guardará en sample.bak

Para editar en línea sin copia de seguridad, use el siguiente comando

 sed -i'' 's/foo/bar/g' sample 

Una cosa a tener en cuenta, sed no puede escribir archivos por sí mismo ya que el único propósito de sed es actuar como editor en la “secuencia” (es decir, canalizaciones de stdin, stdout, stderr y otros >&n buffers, sockets y similares) . Con esto en mente, puede usar otra tee comando para escribir la salida nuevamente en el archivo. Otra opción es crear un parche desde la canalización del contenido a diff .

Método de Tee

sed '/regex/' | tee

Método de parche

sed '/regex/' | diff -p /dev/stdin | patch

ACTUALIZAR:

Además, tenga en cuenta que el parche hará que el archivo cambie de la línea 1 de la salida diff:

Patch no necesita saber a qué archivo acceder ya que se encuentra en la primera línea del resultado de diff:

 $ echo foobar | tee fubar $ sed 's/oo/u/' fubar | diff -p fubar /dev/stdin *** fubar 2014-03-15 18:06:09.000000000 -0500 --- /dev/stdin 2014-03-15 18:06:41.000000000 -0500 *************** *** 1 **** ! foobar --- 1 ---- ! fubar $ sed 's/oo/u/' fubar | diff -p fubar /dev/stdin | patch patching file fubar 

No es posible hacer lo que quieras con sed . Incluso las versiones de sed que admiten la opción -i para editar un archivo en su lugar hacen exactamente lo que usted ha declarado explícitamente que no desea: escriben en un archivo temporal y luego renombran el archivo. Pero quizás solo puedas usar ed . Por ejemplo, para cambiar todas las apariciones de foo a bar en el archivo file.txt , puede hacer:

 echo ',s/foo/bar/g; w' | tr \; '\012' | ed -s file.txt 

La syntax es similar a sed , pero ciertamente no es exactamente lo mismo.

Pero tal vez deberías considerar por qué no quieres usar un archivo temporal renombrado. Incluso si no tiene un -i support sed , puede escribir fácilmente un script para hacer el trabajo por usted. En lugar del sed -i 's/foo/bar/g' file , podría hacer inline file sed 's/foo/bar/g' . Tal script es trivial de escribir. Por ejemplo:

 #!/bin/sh -e IN=$1 shift trap 'rm -f $tmp' 0 tmp=$( mktemp ) < $IN "$@" >$tmp && cat $tmp > $IN # preserve hard links 

debería ser adecuado para la mayoría de los usos.

sed admite edición in situ. Del man sed :

 -i[SUFFIX], --in-place[=SUFFIX] edit files in place (makes backup if extension supplied) 

Ejemplo :

Digamos que tiene un archivo hello.txt con el texto:

 hello world! 

Si desea mantener una copia de seguridad del archivo anterior, use:

 sed -i.bak 's/hello/bonjour' hello.txt 

Usted terminará con dos archivos: hello.txt con el contenido:

 bonjour world! 

y hello.txt.bak con el contenido anterior.

Si no quiere conservar una copia, simplemente no pase el parámetro de extensión.

Puedes usar vi

 vi -c '%s/foo/bar/g' my.txt -c 'wq' 
 mv file.txt file.tmp && sed 's/foo/bar/g' < file.tmp > file.txt 

Debe preservar todos los enlaces duros, ya que la salida se dirige hacia atrás para sobrescribir el contenido del archivo original, y evita la necesidad de una versión especial de sed.

Si está reemplazando la misma cantidad de caracteres y después de leer detenidamente la edición “en el lugar” de los archivos …

También puede usar el operador de redirección <> para abrir el archivo y leer y escribir:

 sed 's/foo/bar/g' file 1<> file 

Véalo en vivo:

 $ cat file hello i am here # see "here" $ sed 's/here/away/' file 1<> file # Run the `sed` command $ cat file hello i am away # this line is changed now 

Manual de referencia de Bash → 3.6.10 Apertura de descriptores de archivo para lectura y escritura :

El operador de redirección

 [n]<>word 

hace que el archivo cuyo nombre es la expansión de la palabra se abra para lectura y escritura en el descriptor de archivo n, o en el descriptor de archivo 0 si n no se especifica. Si el archivo no existe, se crea.

No especificó qué shell está utilizando, pero con zsh podría usar el constructo =( ) para lograr esto. Algo como:

 cp =(sed ... file; sync) file 

=( ) es similar a >( ) pero crea un archivo temporal que se elimina automáticamente cuando termina cp .

Al igual que Moneypenny, dijo en Skyfall: “A veces las formas antiguas son las mejores”. Kincade dijo algo similar más adelante.

$ printf ‘, s / falso / verdadero / g \ nw \ n’ | ed {YourFileHere}

Feliz edición en su lugar. Se agregó ‘\ nw \ n’ para escribir el archivo. Disculpas por la demora en responder la solicitud.

Muy buenos ejemplos. Tuve el reto de editar en el lugar muchos archivos y la opción -i parece ser la única solución razonable que la usa dentro del comando find. Aquí la secuencia de comandos para agregar “versión:” en frente de la primera línea de cada archivo:

 find . -name pkg.json -print -exec sed -i '.bak' '1 s/^/version /' {} \;