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_find
con 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
-i
se 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.CRLF
aLF
en Windows.Tengo la respuesta
fuente
grep
y luego otra vez consed
. Usar elfind
mé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.grep
todos los archivos ysed
solo escanea los archivos que coincidengrep
. Con elfind
método en la otra respuesta,find
primero enumera todos los archivos y luegosed
explorará 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
,grep
yfind
.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
grep
solo es útil si hay archivos que no deben modificarse. La ejecuciónsed
en todos los archivos actualizará la fecha de modificación del archivo, pero dejará el contenido sin cambios si no hay coincidencias.-i
, creo quesed
cambia el tiempo de archivo de cada archivo que toca, a pesar de que el contenido no cambia.sed
También convierte las terminaciones de línea . yo no usosed
en Windows en un repositorio git porque todosCRLF
se 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' -pi
sort -u
parte par de esto? ¿En qué circunstancias esperaríagrep -rl
producir 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
match1
ymatch2
generalmente son idénticos, peromatch1
pueden simplificarse para eliminar características más avanzadas que solo son relevantes para la sustitución, por ejemplo, capturar grupos.Traducción:
grep
recursivamente 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 losxargs
que se espera una lista separada por nul, pero no hará nada si no se reciben nombres, y llegarperl
a sustituir líneas donde se encuentran coincidencias.Agregue el
I
interruptorgrep
para ignorar los archivos binarios. Para la coincidencia entre mayúsculas y minúsculas, suelte eli
interruptorgrep
y lai
bandera adjunta a la expresión de sustitución, pero no eli
interruptor enperl
sí.fuente
find2perl
que se envía con Perl que hace este tipo de cosas sin ningúnxargs
truco.find
no 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
find
ysed
en un repositorio de git! Si no excluye los archivos binarios, puede terminar con este error:Para resolver este error, debe revertirlo
sed
reemplazando sunew_string
con 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
find
y usargrep
en 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
filename
el nombre del archivo debajo de/path/to/dir
, para cada archivo encontrado, busque la línea consearchstring
y reemplaceold
connew
.Sin embargo, si desea omitir la búsqueda de un archivo específico con una
filename
cadena 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 globstar
en 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á recursivamenteSEARCH
conREPLACE
.La
-X
bandera 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' **/*.ext
si quisiera sustituirSEARCH
conREPLACE
en todos los archivos de los niños con la extensión.ext
.fuente
grep
ysed
.