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 comandoxargsrecoge esos nombres de archivo y los entrega uno por uno parasedsed -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
-print0opció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 directorycuando corrofind . -name '*.md' -print0 | xargs -0 sed -i '' -e 's/ä/ä/g', perofind . -name '*.md' -print0da una lista de muchos archivos.-iy el''''después desed -icuál es el''papel?Esto elimina la
xargsdependencia.fuente
sed, por lo que fallará en la mayoría de los sistemas. GNUsedrequiere que no pongas espacio entre-iy''.Si está utilizando Git, puede hacer esto:
-lenumera solo nombres de archivos.-zimprime 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 grepse 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
changeen una carpeta en mi$PATHy lo hicechmod +x change.fuente
Mi caso de uso era lo que quería para reemplazar
foo:/Drive_Letterconfoo:/bar/baz/xyzEn 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
-ia-i ''es probablemente más relevante que el hecho de que cambiaste-execa-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
-Lbandera. La versión final se ve así:fuente