Usando un shell como bash o zshell, ¿cómo puedo hacer un 'buscar y reemplazar' recursivo? En otras palabras, quiero reemplazar cada aparición de 'foo' con 'bar' en todos los archivos en este directorio y sus subdirectorios.
bash
shell
zsh
find-and-replace
Nathan Long
fuente
fuente
Respuestas:
Este comando lo hará (probado en Mac OS X Lion y Kubuntu Linux).
Así es como funciona:
find . -type f -name '*.txt'
encuentra, en el directorio actual (.
) y debajo, todos los archivos regulares (-type f
) cuyos nombres terminan en.txt
|
pasa la salida de ese comando (una lista de nombres de archivo) al siguiente comandoxargs
recoge esos nombres de archivo y los entrega uno por uno parased
sed -i '' -e 's/foo/bar/g'
significa "editar el archivo en su lugar, sin una copia de seguridad, y realizar la siguiente sustitución (s/foo/bar
) varias veces por línea (/g
)" (verman sed
)Tenga en cuenta que la parte 'sin respaldo' en la línea 4 está bien para mí, porque los archivos que estoy cambiando están bajo control de versión de todos modos, por lo que puedo deshacer fácilmente si hubo un error.
fuente
-print0
opción. Su comando fallará en archivos con espacios, etc. en su nombre.find -name '*.txt' -exec sed -i 's/foo/bar/g' {} +
haré todo esto con GNU find.sed: can't read : No such file or directory
cuando corrofind . -name '*.md' -print0 | xargs -0 sed -i '' -e 's/ä/ä/g'
, perofind . -name '*.md' -print0
da una lista de muchos archivos.-i
y el''
''
después desed -i
cuál es el''
papel?Esto elimina la
xargs
dependencia.fuente
sed
, por lo que fallará en la mayoría de los sistemas. GNUsed
requiere que no pongas espacio entre-i
y''
.Si está utilizando Git, puede hacer esto:
-l
enumera solo nombres de archivos.-z
imprime un byte nulo después de cada resultado.Terminé haciendo esto porque algunos archivos en un proyecto no tenían una nueva línea al final del archivo, y agregué una nueva línea incluso cuando no hizo otros cambios. (Sin comentarios sobre si los archivos deberían tener una nueva línea al final. 🙂)
fuente
find ... -print0 | xargs -0 sed ...
soluciones no solo toman mucho más tiempo, sino que también agregan nuevas líneas a los archivos que aún no tienen una, lo cual es una molestia cuando se trabaja dentro de un repositorio git.git grep
se ilumina rápido en comparación.Aquí está mi función zsh / perl que uso para esto:
Y lo ejecutaría usando
(por ejemplo)
fuente
Tratar:
Probado en Ubuntu 12.04.
Este comando NO funcionará si los nombres de subdirectorios y / o nombres de archivos contienen espacios, pero si los tiene, no use este comando ya que no funcionará.
En general, es una mala práctica usar espacios en los nombres de directorio y de archivo.
http://linuxcommand.org/lc3_lts0020.php
Mire "Datos importantes sobre nombres de archivos"
fuente
Utilice este script de shell
Ahora uso este script de shell, que combina cosas que aprendí de las otras respuestas y de la búsqueda en la web. Lo puse en un archivo llamado
change
en una carpeta en mi$PATH
y lo hicechmod +x change
.fuente
Mi caso de uso era lo que quería para reemplazar
foo:/Drive_Letter
confoo:/bar/baz/xyz
En mi caso tuve la oportunidad de hacerlo con el siguiente código. Estaba en la misma ubicación del directorio donde había gran cantidad de archivos.Espero que haya ayudado.
fuente
El siguiente comando funcionó bien en Ubuntu y CentOS; sin embargo, bajo OS XI seguía recibiendo errores:
Cuando intenté pasar los parámetros a través de xargs funcionó bien sin errores:
fuente
-i
a-i ''
es probablemente más relevante que el hecho de que cambiaste-exec
a-print0 | xargs -0
. Por cierto, probablemente no necesites el-e
.Lo anterior funcionó a las mil maravillas, pero con los directorios vinculados, debo agregarle una
-L
bandera. La versión final se ve así:fuente