Búsqueda recursiva y reemplazo en archivos de texto en Mac y Linux


127

En el shell de Linux, el siguiente comando buscará y reemplazará recursivamente todas las instancias de 'this' con 'that' (no tengo un shell de Linux frente a mí, pero debería hacerlo).

find . -name "*.txt" -print | xargs sed -i 's/this/that/g'

¿Cómo será un comando similar en OSX?


Probablemente debería mudarse apple.stackexchange.comya que no es lo suficientemente genérico para Linux ni para todos los desarrolladores.
— AlikElzin-kilaka

Respuestas:


246

OS X utiliza una combinación de herramientas BSD y GNU, por lo que es mejor consultar siempre la documentación (aunque tenía una que lessni siquiera se ajustaba a la página de manual de OS X):

https://web.archive.org/web/20170808213955/https://developer.apple.com/legacy/library/documentation/Darwin/Reference/ManPages/man1/sed.1.html

sed toma el argumento después -icomo la extensión para las copias de seguridad. Proporcione una cadena vacía ( -i '') para que no haya copias de seguridad.

Lo siguiente debería hacer:

LC_ALL=C find . -type f -name '*.txt' -exec sed -i '' s/this/that/ {} +

El -type fes solo una buena práctica; sed se quejará si le das un directorio más o menos. -execse prefiere sobre xargs; no necesitas molestarte -print0ni nada. Al {} +final significa que findagregará todos los resultados como argumentos a una instancia del comando llamado, en lugar de volver a ejecutarlo para cada resultado. (Una excepción es cuando se infringe el número máximo de argumentos de línea de comandos permitidos por el sistema operativo; en ese caso findse ejecutará más de una instancia).


2
Mi "this" en esta sustitución contiene una barra diagonal (localhost / sitio): estoy sustituyendo partes de una URL en un archivo .html ... ¿cómo hago tal sustitución? Intenté poner comillas dobles, pero falla.
— Timothy T.

66
Sed sintaxis permite utilizar casi cualquier carácter en lugar de la barra, por ejemplo, se puede utilizar el %carácter: sed "s%localhost/site%blah/blah%". Otra alternativa es la barra invertida-escapar del separador: sed "s/localhost\/site/blah\/blah/".
— TaylanUB

Gracias déjame probar eso. Sin embargo, intenté usar {} para separar la barra diagonal y aún recibí un error ...
— Timothy T.

16
¿Alguien más recibe un illegal byte sequenceerror? si es así, intente: LC_ALL=C find . -type f -name '*.txt' -exec sed -i '' s/this/that/ {} +funcionó para mí.
— ColdTuna

10
Esto reemplazará solo una ocurrencia por archivo, use /gpara múltiples ocurrencias comoLC_ALL=C find . -type f -exec sed -i '' s/search/replace/g {} +
— jamesjara

152

Para el mac, un enfoque más similar sería este:

find . -name '*.txt' -print0 | xargs -0 sed -i "" "s/form/forms/g"

10
Desearía poder votar esto cada vez que vuelva a usarlo. Ya estaría en +15, fácil.
— Droogans

Por alguna razón, no funciona para mí. No hace nada Estoy dentro de la carpeta form360 y estoy tratando de cambiar todas las instancias de cadena con el nombre easyform a form360, estoy ejecutando el siguiente comando:find . -name '*.php' -print0 | xargs -0 sed -i "" "s/easyform/form360/g"
— Andres Ramos

2
Para mí, esta debería ser la respuesta correcta. Es el único que funcionó para mí.
— nosequeldeebee

1
-print0 | xargs -0 no funciona en mi mac cuando el nombre del archivo contiene espacio.
— user2807219

1
. sed:: en lugar de editar sólo funciona para los archivos normales
— codeslapper

14

Como solución alternativa, estoy usando esta en Mac OSX 10.7.5

grep -ilr 'old-word' * | xargs -I@ sed -i '' 's/old-word/new-word/g' @

El crédito es para: la respuesta de Todd Cesere


Este funciona bien! ¡Otros scripts agregan un final de línea adicional en algunos casos en OSX! ¡Muchas gracias!
— Sebastien Filion

14

En Mac OSX 10.11.5 esto funciona bien:

grep -rli 'old-word' * | xargs -I@ sed -i '' 's/old-word/new-word/g' @

xargs -I @ sed -i '' 's / old-word / new-word / g' @ funcionó para mí después de probar tantas otras sugerencias que no funcionan. ¡Gracias!
— DrB

13

Ninguno de los anteriores funciona en OSX.

Haz lo siguiente:

perl -pi -w -e 's/SEARCH_FOR/REPLACE_WITH/g;' *.txt

1
¿Cómo escapar '/' si SEARCH_FOR y REPLACE_WITH son rutas?
— rraallvv

Usa un delimitador diferente. Si está utilizando rutas, dos puntos o una tubería funcionarían. 's | SEARCH | REPLACE | g', por ejemplo. Nuestro uso de llaves, como en 's {SEARCH} {REPLACE}'.
— dannysauer

1
Pregunta de dito, intentando no en Mac, pero parece generar un error. Por ejemplo, ¿mi ruta se interpreta como un archivo? -bash: localhost / nohost: No existe tal archivo o directorio
— Timothy T.

esto no se repite a través de carpetas profundas. Solo un nivel.
— Sergey Romanov

Para obtener más información sobre este comando leer este lifehacker.com/5810026/...
— kuzdu

7

Una versión que funciona tanto en Linux como en Mac OS X (agregando el -einterruptor a sed):

export LC_CTYPE=C LANG=C
find . -name '*.txt' -print0 | xargs -0 sed -i -e 's/this/that/g'

Tuve que hacer la exportación de esta respuesta + la línea de la respuesta aceptada (no quería que se generaran archivos de respaldo)
— Lance

2
para abordar el error 'secuencia de bytes ilegal', intente configurar LOCALE antes de ejecutar el comando: export LC_CTYPE=C && export LANG=C
— disfrute el

NUNCA EJECUTE esto con '*' en lugar de '* .filetype' como lo hice si está usando Git. O puedes despedirte de todo tu trabajo inédito.
— Sergey

1
La versión mac del comando sed requiere un '' después de -i, por lo que esta respuesta es incorrecta
— G Huxley

2

Cada vez que escribo este comando, parece que siempre lo manguito u olvido una bandera. Creé un Gist en github basado en la respuesta de TaylanUB que hace un reemplazo global del directorio actual. Esto es específico de Mac OSX.

https://gist.github.com/nateflink/9056302

Es bueno porque ahora solo abro una terminal y luego copio:

curl -s https://gist.github.com/nateflink/9056302/raw/findreplaceosx.sh | bash -s "find-a-url.com" "replace-a-url.com"

Puede obtener algunos errores de secuencia de bytes extraños, así que aquí está el código completo:

#!/bin/bash
#By Nate Flink

#Invoke on the terminal like this
#curl -s https://gist.github.com/nateflink/9056302/raw/findreplaceosx.sh | bash -s "find-a-url.com" "replace-a-url.com"

if [ -z "$1" ] || [ -z "$2" ]; then
  echo "Usage: ./$0 [find string] [replace string]"
  exit 1
fi

FIND=$1
REPLACE=$2

#needed for byte sequence error in ascii to utf conversion on OSX
export LC_CTYPE=C;
export LANG=C;

#sed -i "" is needed by the osx version of sed (instead of sed -i)
find . -type f -exec sed -i "" "s|${FIND}|${REPLACE}|g" {} +
exit 0

2

Este es mi viable. en mac OS X 10.10.4

grep -e 'this' -rl . | xargs sed -i '' 's/this/that/g'

Los anteriores usan find para cambiar los archivos que no contienen el texto de búsqueda (agregue una nueva línea al final del archivo), que es detallado.


2

Si está utilizando un terminal zsh, puede usar comodines mágicos:

sed -i "" "s/search/high-replace/g" *.txt


1

Utilicé este formato, pero ... descubrí que tenía que ejecutarlo tres o más veces para que cambiara cada instancia, lo que me pareció extremadamente extraño. Ejecutarlo una vez cambiaría algunos en cada archivo pero no todos. Ejecutar exactamente la misma cadena dos o cuatro veces capturaría todas las instancias.

find . -type f -name '*.txt' -exec sed -i '' s/thistext/newtext/ {} +

Necesitabas ejecutar este comando varias veces b / c, tu sed regex necesita ga al final, de lo contrario solo reemplaza la primera aparición de thistexten una línea. Entonces tu expresión regular debería sers/thistext/newtext/g
— Les Nightingill

0

https://bitbucket.org/masonicboom/serp es una utilidad go (es decir, multiplataforma), probada en OSX, que realiza búsquedas y reemplazos recursivos de texto en archivos dentro de un directorio dado, y confirma cada reemplazo. Es nuevo, por lo que podría tener errores.

El uso se ve así:

$ ls test
a  d  d2 z
$ cat test/z
hi
$ ./serp --root test --search hi --replace bye --pattern "*"                         
test/z: replace hi with bye? (y/[n]) y
$ cat test/z
bye


-3

El comando en OSX debe ser exactamente el mismo que en Unix bajo la bonita interfaz de usuario.


Lo pensé mucho, pero no. Pone un ./ delante de los archivos cuando se alimenta a sed, por lo que sed se queja de "código de comando no válido". Tal vez solo estoy cansado ;-)
— Jack

@JacobusR, corta y pega desde tu terminal OSX; debes ingresar algo ligeramente diferente.
— Glenn Jackman

3
Es posible que desee -print0agregar a las findbanderas y -0a las xargsbanderas.
— jmtd

También puede usar en -exec sed -i s/this/that/g {} \+lugar de -printy xargs
— Marian

@JacobusR: esto funciona, incluso si hay un nombre de ruta './' principal. Sin embargo, si hay un espacio en el nombre del archivo, diga "./jacobus \ R.txt", el uso de xargspodría ver el delimitado por espacios "./jacobus" como un archivo para pasar sed, y luego con "R.txt" , ninguno de los cuales existe.
— Brett Hale

Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.