¿Cómo hacer un hallazgo recursivo / reemplazar una cadena con awk o sed?

¿Cómo puedo encontrar y reemplazar cada ocurrencia de:

subdomainA.example.com 

con

 subdomainB.example.com 

en cada archivo de texto en el árbol de directorio /home/www/ recursivamente?

Nota : No ejecute este comando en una carpeta que incluya un repository de git: los cambios en .git podrían dañar su índice de git.

 find /home/www -type f -print0 | xargs -0 sed -i 's/subdomainA\.example\.com/subdomainB.example.com/g' 

Del man find :

-print0 (sólo GNU find) le dice a find que use el carácter nulo (\ 0) en lugar de espacios en blanco como el delimitador de salida entre las rutas encontradas. Esta es una opción más segura si sus archivos pueden contener espacios en blanco u otro carácter especial. Se recomienda utilizar el argumento -print0 para encontrar si usa el comando -exec o xargs (el argumento -0 es necesario en xargs).

Nota : No ejecute este comando en una carpeta que incluya un repository de git: los cambios en .git podrían dañar su índice de git.

 find /home/www/ -type f -exec \ sed -i 's/subdomainA\.example\.com/subdomainB.example.com/g' {} + 

Comparado con otras respuestas aquí, esto es más simple que la mayoría y usa sed en lugar de perl, que es lo que la pregunta original solicitó.

La forma más sencilla para mí es

 grep -rl oldtext . | xargs sed -i 's/oldtext/newtext/g' 

Todos los trucos son casi lo mismo, pero me gusta este:

 find  -type f -exec sed -i 's///g' {} + 
  • find : busca en el directorio.

  • -type f :

    El archivo es del tipo: archivo regular

  • -exec command {} + :

    Esta variante de la acción -exec ejecuta el comando especificado en los archivos seleccionados, pero la línea de comando se construye agregando cada nombre de archivo seleccionado al final; el número total de invocaciones del comando será mucho menor que el número de archivos coincidentes. La línea de comando está construida de la misma manera que xargs construye sus líneas de comando. Solo se permite una instancia de `{} ‘dentro del comando. El comando se ejecuta en el directorio de inicio.

 cd /home/www && find . -type f -print0 | xargs -0 perl -i.bak -pe 's/subdomainA\.example\.com/subdomainB.example.com/g' 

Para mí, la solución más fácil de recordar es https://stackoverflow.com/a/2113224/565525 , es decir:

 sed -i '' -e 's/subdomainA/subdomainB/g' $(find /home/www/ -type f) 

NOTA : -i '' resuelve el problema de OSX sed: 1: "...": invalid command code .

NOTA : Si hay demasiados archivos para procesar, obtendrá una Argument list too long . La solución alternativa: use la solución find -exec o find -exec descrita anteriormente.

Para cualquier persona que use silver searcher ( ag )

 ag SearchString -l0 | xargs -0 sed -i 's/SearchString/Replacement/g' 

Como ag ignora git / hg / svn file / folders de forma predeterminada, es seguro ejecutarlo dentro de un repository.

Para reducir los archivos a través de los que sed recursivamente, puede grep para su instancia de cadena:

 grep -rl  /path/to/folder | xargs sed -is^^^g 

Si ejecuta man grep , notará que también puede definir un --exlude-dir="*.git" si quiere omitir la búsqueda a través de los directorios .git, evitando los problemas del índice git como otros señalaron amablemente.

Guiando a:

 grep -rl --exclude-dir="*.git"  /path/to/folder | xargs sed -is^^^g 

Un buen oneliner como extra. Usando git grep.

 git grep -lz 'subdomainA.example.com' | xargs -0 perl -i'' -pE "s/subdomainA.example.com/subdomainB.example.com/g" 

Este es compatible con repositorys git, y un poco más simple:

Linux:

 git grep -l 'original_text' | xargs sed -i 's/original_text/new_text/g' 

Mac:

 git grep -l 'original_text' | xargs sed -i '' -e 's/original_text/new_text/g' 

(Gracias a http://blog.jasonmeridth.com/posts/use-git-grep-to-replace-strings-in-files-in-your-git-repository/ )

Simplemente necesitaba esto y no estaba contento con la velocidad de los ejemplos disponibles. Así que se me ocurrió el mío:

 cd /var/www && ack-grep -l --print0 subdomainA.example.com | xargs -0 perl -i.bak -pe 's/subdomainA\.example\.com/subdomainB.example.com/g' 

Ack-grep es muy eficiente en la búsqueda de archivos relevantes. Este comando reemplazó ~ 145 000 archivos con una brisa, mientras que otros tardaron tanto que no pude esperar hasta que terminen.

 find /home/www/ -type f -exec perl -i.bak -pe 's/subdomainA\.example\.com/subdomainB.example.com/g' {} + 

find /home/www/ -type f todos los archivos en / home / www / (y sus subdirectorios). El indicador “-exec” le dice a find que ejecute el siguiente comando en cada archivo encontrado.

 perl -i.bak -pe 's/subdomainA\.example\.com/subdomainB.example.com/g' {} + 

es el comando ejecutado en los archivos (muchos a la vez). El {} se reemplaza por nombres de archivo. El + al final del comando le dice a find que construya un comando para muchos nombres de archivo.

Según la página de find hombre: “La línea de comando está construida de la misma manera que xargs construye sus líneas de comando”.

Por lo tanto, es posible lograr su objective (y manejar nombres de archivo que contengan espacios) sin usar xargs -0 o -print0 .

grep -lr 'subdomainA.example.com' | while read file; do sed -i "s/subdomainA.example.com/subdomainB.example.com/g" "$file"; done

Supongo que la mayoría de la gente no sabe que puede canalizar algo en un “archivo de lectura simultánea” y evita esos molestos argumentos de impresión, al tiempo que inventa espacios en los nombres de archivos.

Además, agregar un echo antes del sed le permite ver qué archivos cambiarán antes de hacerlo realmente.

Puedes usar awk para resolver esto de la siguiente manera:

 for file in `find /home/www -type f` do awk '{gsub(/subdomainA.example.com/,"subdomainB.example.com"); print $0;}' $file > ./tempFile && mv ./tempFile $file; done 

Espero que esto te ayudará !!!

Prueba esto:

 sed -i 's/subdomainA/subdomainB/g' `grep -ril 'subdomainA' *` 
 #!/usr/local/bin/bash -x find * /home/www -type f | while read files do sedtest=$(sed -n '/^/,/$/p' "${files}" | sed -n '/subdomainA/p') if [ "${sedtest}" ] then sed s'/subdomainA/subdomainB/'g "${files}" > "${files}".tmp mv "${files}".tmp "${files}" fi done 

Si no te importa usar vim junto con grep o find herramientas, puedes seguir la respuesta dada por el usuario Gert en este enlace -> ¿Cómo hacer un reemplazo de texto en una gran jerarquía de carpetas? .

Aquí está el trato:

  • recursivamente grep para la cadena que desea reemplazar en una ruta determinada, y tomar solo la ruta completa del archivo correspondiente. ( $(grep 'string' 'pathname' -Rl) sería la $(grep 'string' 'pathname' -Rl) .

  • (opcional) si desea hacer una pre-copia de seguridad de esos archivos en el directorio centralizado, tal vez pueda usar esto también: cp -iv $(grep 'string' 'pathname' -Rl) 'centralized-directory-pathname'

  • después de eso puede editar / reemplazar a voluntad en vim siguiendo un esquema similar al proporcionado en el enlace dado:

    • :bufdo %s#string#replacement#gc | update

solo para evitar cambiar también

  • NearlysubdomainA.example.com
  • subdomainA.example.comp.other

pero aún

  • subdomainA.example.com.IsIt.good

(tal vez no es bueno en la idea detrás de la raíz del dominio)

 find /home/www/ -type f -exec sed -i 's/\bsubdomainA\.example\.com\b/\1subdomainB.example.com\2/g' {} \; 

De acuerdo con esta publicación en el blog:

 find . -type f | xargs perl -pi -e 's/oldtext/newtext/g;' 

Para Qshell (qsh) en IBMi, no bash como etiquetado por OP.

Limitaciones de los comandos qsh:

  • find no tiene la opción -print0
  • xargs no tiene la opción -0
  • sed no tiene la opción -i

Por lo tanto, la solución en qsh:

  PATH='your/path/here' SEARCH=\'subdomainA.example.com\' REPLACE=\'subdomainB.example.com\' for file in $( find ${PATH} -P -type f ); do TEMP_FILE=${file}.${RANDOM}.temp_file if [ ! -e ${TEMP_FILE} ]; then touch -C 819 ${TEMP_FILE} sed -e 's/'$SEARCH'/'$REPLACE'/g' \ < ${file} > ${TEMP_FILE} mv ${TEMP_FILE} ${file} fi done 

Advertencias:

  • La solución no incluye el manejo de errores
  • Not Bash etiquetado por OP

Si quería usar esto sin destruir por completo su repository SVN, puede decirle a ‘find’ que ignore todos los archivos ocultos haciendo lo siguiente:

 find . \( ! -regex '.*/\..*' \) -type f -print0 | xargs -0 sed -i 's/subdomainA.example.com/subdomainB.example.com/g' 

Usando la combinación de grep y sed

 for pp in $(grep -Rl looking_for_string) do sed -i 's/looking_for_string/something_other/g' "${pp}" done 

Un poco vieja escuela pero esto funcionó en OS X.

Hay pocos trucos:

• Solo editará archivos con extensión .sls bajo el directorio actual

. debe escaparse para garantizar que sed no los evalúe como “cualquier personaje”

, se usa como el delimitador de sed lugar del habitual /

También tenga en cuenta que esto es para editar una plantilla Jinja para pasar una variable en la ruta de una import (pero esto está fuera de tema).

Primero, verifica que tu comando sed haga lo que quieras (esto solo imprimirá los cambios en stdout, no cambiará los archivos):

 for file in $(find . -name *.sls -type f); do echo -e "\n$file: "; sed 's,foo\.bar,foo/bar/\"+baz+\"/,g' $file; done 

Edite el comando sed según sea necesario, una vez que esté listo para hacer cambios:

 for file in $(find . -name *.sls -type f); do echo -e "\n$file: "; sed -i '' 's,foo\.bar,foo/bar/\"+baz+\"/,g' $file; done 

Tenga en cuenta el -i '' en el comando sed , no quería crear una copia de seguridad de los archivos originales (como se explica en las ediciones in situ con sed en OS X o en el comentario de Robert Lujo en esta página).

Happy seding gente!

 perl -p -i -e 's/oldthing/new_thingy/g' `grep -ril oldthing *` 

para cambiar varios archivos (y guardar una copia de seguridad como *.bak ):

 perl -p -i -e "s/\|/x/g" * 

tomará todos los archivos en el directorio y reemplazará | con x llamado “pastel Perl” (fácil como un pastel)

Solo uso tops:

 find . -name '*.[c|cc|cp|cpp|m|mm|h]' -print0 | xargs -0 tops -verbose replace "verify_noerr()" with "__Verify_noErr()" \ replace "check()" with "__Check()" 

Una forma más simple es usar lo siguiente en la línea de comando

 find /home/www/ -type f|xargs perl -pi -e 's/subdomainA\.example\.com/subdomainB.example.com/g' 

Esta es la mejor solución para todos que he encontrado para OSX y Windows (msys2). Debería funcionar con cualquier cosa que pueda obtener la versión gnu de sed. Salta los directorios .git para que no corrompa tus sums de comprobación.

En Mac, simplemente instale coreutils primero y asegúrese de que gsed esté en el camino –

 brew install coreutils 

Luego guardo esta función en mi zshrc / bashrc ->

 replace-recursive() { hash gsed 2>/dev/null && local SED_CMD="gsed" || SED_CMD="sed" find . -type f -name "*.*" -not -path "*/.git/*" -print0 | xargs -0 $SED_CMD -i "s/$1/$2/g" } usage: replace-recursive   

Para reemplazar todo el contenido que coincida con string_1 con string_2 de todos los archivos .c y .h en el directorio actual y los subdirectorios (excluyendo .git /) .

Esto funciona en Mac :

 find . -type f -path "*.git*" -prune -o -name '*\.[ch]' -exec \ sed -i '' -e 's/'$1'/'$2'/g' {} + 

Esto debería funcionar en Linux (aún no probado):

 find . -type f -path "*.git*" -prune -o -name '*\.[ch]' -exec \ sed -i 's/string_1/string_2/g' {} + 

Si tiene acceso al nodo, puede hacer una npm install -g rexreplace y luego

 rexreplace 'subdomainA.example.com' 'subdomainB.example.com' /home/www/**/*.*