Necesito buscar recursivamente una cadena especificada dentro de todos los archivos y subdirectorios dentro de un directorio y reemplazar esta cadena con otra cadena.
Sé que el comando para encontrarlo podría verse así:
grep 'string_to_find' -r ./*
Pero, ¿cómo puedo reemplazar cada instancia de string_to_findcon otra cadena?

sed -i 's/.*substring.*/replace/'sed -i 's/\(.*\)substring\(.*\)/\1replace\2/'Respuestas:
Otra opción es usar find y luego pasarlo a través de sed.
fuente
-ise requiere una cadena de extensión adecuada para el parámetro . Por ejemplo, defind /path/to/files -type f -exec sed -i "" "s/oldstring/new string/g" {} \;todos modos, proporcionar una cadena vacía aún crea un archivo de copia de seguridad diferente al descrito en el manual ...-i ""para OS X. Funciona de otra manera.CRLFaLFen Windows.Tengo la respuesta
fuente
grepy luego otra vez consed. Usar elfindmétodo es más eficiente, pero este método que mencionas funciona.sed -i 's/str1/str2/g'ased -i "" 's/str1/str2/g'para que esto funcione.greptodos los archivos ysedsolo escanea los archivos que coincidengrep. Con elfindmétodo en la otra respuesta,findprimero enumera todos los archivos y luegosedexplorará todos los archivos en ese directorio. Por lo tanto, este método no es necesariamente más lento, depende de cuántas coincidencias hay y las diferencias en las velocidades de búsqueda entresed,grepyfind.Incluso podrías hacerlo así:
Ejemplo
Esto buscará la cadena ' windows ' en todos los archivos relativos al directorio actual y reemplazará ' windows ' con ' linux ' para cada aparición de la cadena en cada archivo.
fuente
grepsolo es útil si hay archivos que no deben modificarse. La ejecuciónseden todos los archivos actualizará la fecha de modificación del archivo, pero dejará el contenido sin cambios si no hay coincidencias.-i, creo quesedcambia el tiempo de archivo de cada archivo que toca, a pesar de que el contenido no cambia.sedTambién convierte las terminaciones de línea . yo no usoseden Windows en un repositorio git porque todosCRLFse cambian aLF.Esto funciona mejor para mí en OS X:
Fuente: http://www.praj.com.au/post/23691181208/grep-replace-text-string-in-files
fuente
ag "search" -l -r . | sort | uniq | xargs perl -e 's/search/replace' -pisort -uparte par de esto? ¿En qué circunstancias esperaríagrep -rlproducir el mismo nombre de archivo dos veces?Otras soluciones mezclan sintaxis de expresiones regulares. Para usar patrones perl / PCRE para tanto buscar y reemplazar, y sólo los archivos coincidentes del proceso, esto funciona bastante bien:
dónde
match1ymatch2generalmente son idénticos, peromatch1pueden simplificarse para eliminar características más avanzadas que solo son relevantes para la sustitución, por ejemplo, capturar grupos.Traducción:
greprecursivamente y enumere los archivos que coinciden con este patrón PCRE, separados por nul para proteger cualquier carácter especial en el nombre del archivo, luego canalice los nombres de archivo a losxargsque se espera una lista separada por nul, pero no hará nada si no se reciben nombres, y llegarperla sustituir líneas donde se encuentran coincidencias.Agregue el
Iinterruptorgreppara ignorar los archivos binarios. Para la coincidencia entre mayúsculas y minúsculas, suelte eliinterruptorgrepy laibandera adjunta a la expresión de sustitución, pero no eliinterruptor enperlsí.fuente
find2perlque se envía con Perl que hace este tipo de cosas sin ningúnxargstruco.findno busca el contenido del archivo, y el punto es procesar solo los archivos coincidentes sin escribir un programa Perl.Por lo general, no con grep, sino con
sed -i 's/string_to_find/another_string/g'operl -i.bak -pe 's/string_to_find/another_string/g'.fuente
¡Tenga mucho cuidado al usar
findyseden un repositorio de git! Si no excluye los archivos binarios, puede terminar con este error:Para resolver este error, debe revertirlo
sedreemplazando sunew_stringcon suold_string. Esto revertirá las cadenas reemplazadas, por lo que volverá al comienzo del problema.La forma correcta de buscar una cadena y reemplazarla es omitir
findy usargrepen su lugar para ignorar los archivos binarios:Créditos para @hobs
fuente
Esto es lo que haría:
Esto buscará todos los archivos que contengan
filenameel nombre del archivo debajo de/path/to/dir, para cada archivo encontrado, busque la línea consearchstringy reemplaceoldconnew.Sin embargo, si desea omitir la búsqueda de un archivo específico con una
filenamecadena en el nombre del archivo, simplemente haga lo siguiente:Esto hará lo mismo arriba, pero para todos los archivos encontrados debajo
/path/to/dir.fuente
Otra opción sería simplemente usar perl con globstar.
La activación
shopt -s globstaren su.bashrc(o donde sea) permite que el**patrón global coincida con todos los subdirectorios y archivos de forma recursiva.Por lo tanto, el uso
perl -pXe 's/SEARCH/REPLACE/g' -i **se reemplazará recursivamenteSEARCHconREPLACE.La
-Xbandera le dice a Perl que "desactive todas las advertencias", lo que significa que no se quejará de los directorios.El Globstar también le permite hacer cosas como
sed -i 's/SEARCH/REPLACE/g' **/*.extsi quisiera sustituirSEARCHconREPLACEen todos los archivos de los niños con la extensión.ext.fuente
grepysed.