GNU/Linux >> Tutoriales Linux >  >> Linux

¿Cómo reemplazar una cadena en un archivo (s)?

Reemplazar cadenas en archivos según ciertos criterios de búsqueda es una tarea muy común. ¿Cómo puedo?

  • reemplazar cadena foo con bar en todos los archivos del directorio actual?
  • hacer lo mismo recursivamente para subdirectorios?
  • ¿reemplazar solo si el nombre del archivo coincide con otra cadena?
  • ¿reemplazar solo si la cadena se encuentra en un contexto determinado?
  • ¿reemplazar si la cadena está en un determinado número de línea?
  • reemplace varias cadenas con el mismo reemplazo
  • reemplazar múltiples cadenas con diferentes reemplazos

Respuesta aceptada:

1. Reemplazando todas las apariciones de una cadena con otra en todos los archivos en el directorio actual:

Estos son para casos en los que sabe que el directorio contiene solo archivos normales y que desea procesar todos los archivos no ocultos. Si ese no es el caso, use los enfoques en 2.

Todo sed las soluciones en esta respuesta asumen GNU sed . Si usa FreeBSD o macOS, reemplace -i con -i '' . También tenga en cuenta que el uso de -i cambiar con cualquier versión de sed tiene ciertas implicaciones para la seguridad del sistema de archivos y no es aconsejable en ningún script que planee distribuir de alguna manera.

  • Archivos no recursivos, solo en este directorio:

     sed -i -- 's/foo/bar/g' *
     perl -i -pe 's/foo/bar/g' ./* 
    

(el perl uno fallará para los nombres de archivo que terminan en | o espacio)).

  • Archivos regulares recursivos (incluidos los ocultos ) en este y todos los subdirectorios

     find . -type f -exec sed -i 's/foo/bar/g' {} +
    

    Si está utilizando zsh:

     sed -i -- 's/foo/bar/g' **/*(D.)
    

    (puede fallar si la lista es demasiado grande, consulte zargs para evitarlo).

    Bash no puede buscar archivos regulares directamente, se necesita un bucle (las llaves evitan configurar las opciones globalmente):

     ( shopt -s globstar dotglob;
         for file in **; do
             if [[ -f $file ]] && [[ -w $file ]]; then
                 sed -i -- 's/foo/bar/g' "$file"
             fi
         done
     )
    

    Los archivos se seleccionan cuando son archivos reales (-f) y se pueden escribir (-w).

2. Reemplace solo si el nombre del archivo coincide con otra cadena/tiene una extensión específica/es de cierto tipo, etc.:

  • Archivos no recursivos, solo en este directorio:

    sed -i -- 's/foo/bar/g' *baz*    ## all files whose name contains baz
    sed -i -- 's/foo/bar/g' *.baz    ## files ending in .baz
    
  • Archivos regulares recursivos en este y todos los subdirectorios

    find . -type f -name "*baz*" -exec sed -i 's/foo/bar/g' {} +
    

    Si está utilizando bash (las llaves evitan configurar las opciones globalmente):

    ( shopt -s globstar dotglob
        sed -i -- 's/foo/bar/g' **baz*
        sed -i -- 's/foo/bar/g' **.baz
    )
    

    Si está utilizando zsh:

    sed -i -- 's/foo/bar/g' **/*baz*(D.)
    sed -i -- 's/foo/bar/g' **/*.baz(D.)
    

El -- sirve para decirle a sed que no se darán más banderas en la línea de comando. Esto es útil para proteger contra los nombres de archivo que comienzan con - .

  • Si un archivo es de cierto tipo, por ejemplo, ejecutable (ver man find para más opciones):

    find . -type f -executable -exec sed -i 's/foo/bar/g' {} +
    

zsh :

    sed -i -- 's/foo/bar/g' **/*(D*)

3. Reemplace solo si la cadena se encuentra en un contexto determinado

  • Reemplazar foo con bar solo si hay un baz más adelante en la misma línea:

     sed -i 's/foo(.*baz)/bar1/' file
    

En sed , usando ( ) guarda lo que está entre paréntesis y luego puede acceder a él con 1 . Hay muchas variaciones de este tema, para obtener más información sobre estas expresiones regulares, consulta aquí.

  • Reemplazar foo con bar solo si foo se encuentra en la columna 3d (campo) del archivo de entrada (asumiendo campos separados por espacios en blanco):

     gawk -i inplace '{gsub(/foo/,"baz",$3); print}' file
    

(necesita gawk 4.1.0 o posterior).

  • Para un campo diferente, simplemente use $N donde N es el número del campo de interés. Para un separador de campo diferente (: en este ejemplo) use:

     gawk -i inplace -F':' '{gsub(/foo/,"baz",$3);print}' file
    

Otra solución usando perl :

    perl -i -ane '$F[2]=~s/foo/baz/g; $" = " "; print "@Fn"' foo 

NOTA:tanto el awk y perl las soluciones afectarán el espacio en el archivo (elimine los espacios en blanco iniciales y finales, y convierta las secuencias de espacios en blanco en un carácter de espacio en aquellas líneas que coincidan). Para un campo diferente, use $F[N-1] donde N es el número de campo que desea y para usar un separador de campo diferente (el $"=":" establece el separador de campo de salida en : ):

    perl -i -F':' -ane '$F[2]=~s/foo/baz/g; $"=":";print "@F"' foo 
  • Reemplazar foo con bar sólo en la 4ª línea:

     sed -i '4s/foo/bar/g' file
     gawk -i inplace 'NR==4{gsub(/foo/,"baz")};1' file
     perl -i -pe 's/foo/bar/g if $.==4' file
    

4. Múltiples operaciones de reemplazo:reemplazar con diferentes cadenas

  • Puedes combinar sed comandos:

     sed -i 's/foo/bar/g; s/baz/zab/g; s/Alice/Joan/g' file
    

Tenga en cuenta que el orden importa (sed 's/foo/bar/g; s/bar/baz/g' sustituirá foo con baz ).

  • o comandos Perl

     perl -i -pe 's/foo/bar/g; s/baz/zab/g; s/Alice/Joan/g' file
    
  • Si tiene una gran cantidad de patrones, es más fácil guardar sus patrones y sus reemplazos en un sed archivo de secuencia de comandos:

     #! /usr/bin/sed -f
     s/foo/bar/g
     s/baz/zab/g
    
  • O bien, si tiene demasiados pares de patrones para que lo anterior sea factible, puede leer los pares de patrones de un archivo (dos patrones separados por espacios, $patrón y $reemplazo, por línea):

     while read -r pattern replacement; do   
         sed -i "s/$pattern/$replacement/" file
     done < patterns.txt
    
  • Eso será bastante lento para largas listas de patrones y grandes archivos de datos, por lo que es posible que desee leer los patrones y crear un sed guión de ellos en su lugar. Lo siguiente asume un <espacio> el delimitador separa una lista de COINCIDIR<espacio>REEMPLAZAR pares que ocurren uno por línea en el archivo patterns.txt :

     sed 's| *([^ ]*) *([^ ]*).*|s/1/2/g|' <patterns.txt |
     sed -f- ./editfile >outfile
    

El formato anterior es en gran medida arbitrario y, por ejemplo, no permite un <espacio> en cualquiera de PARTIDO o REEMPLAZAR . Sin embargo, el método es muy general:básicamente, si puede crear un flujo de salida que se parece a un sed secuencia de comandos, entonces puede generar esa transmisión como un sed secuencia de comandos especificando sed archivo de script como - estándar.

  • Puede combinar y concatenar varios scripts de manera similar:

     SOME_PIPELINE |
     sed -e'#some expression script'  
         -f./script_file -f-          
         -e'#more inline expressions' 
     ./actual_edit_file >./outfile
    

Un POSIX sed concatenará todos los scripts en uno en el orden en que aparecen en la línea de comandos. Ninguno de estos necesita terminar en un n nueva línea.

  • grep puede funcionar de la misma manera:

     sed -e'#generate a pattern list' <in |
     grep -f- ./grepped_file
    
  • Cuando se trabaja con cadenas fijas como patrones, es una buena práctica escapar de los metacaracteres de expresiones regulares. . Puedes hacer esto con bastante facilidad:

     sed 's/[]$&^*./[]/\&/g
          s| *([^ ]*) *([^ ]*).*|s/1/2/g|
     ' <patterns.txt |
     sed -f- ./editfile >outfile
    

5. Múltiples operaciones de reemplazo:reemplaza múltiples patrones con la misma cadena

  • Reemplace cualquiera de foo , bar o baz con foobar

     sed -Ei 's/foo|bar|baz/foobar/g' file
    
  • o

     perl -i -pe 's/foo|bar|baz/foobar/g' file
    

Linux
  1. ¿Cómo se reemplaza el texto similar a sed con python?

  2. Eliminar ocurrencias de cadena en archivo de texto

  3. ¿Cómo insertar un texto al principio de un archivo?

  4. Comando tr:cómo reemplazar la cadena \n con una nueva línea real (\n)

  5. sed:¿cómo reemplazar la línea si se encuentra o agregar al final del archivo si no se encuentra?

Cómo usar sed para buscar y reemplazar cadenas en archivos

Cómo encontrar una cadena en un archivo en Linux

Sustitución de cadena en Bash

Cómo usar el comando SED para buscar y reemplazar cadenas en archivos

Cómo buscar y reemplazar texto, palabra o cadena en un archivo

Cómo usar Sed para buscar y reemplazar una cadena en un archivo