¿Cómo reemplazar una cadena en la quinta línea de múltiples archivos de texto?

22

Quiero reemplazar la quinta línea de múltiples archivos de texto ( file1.txt, file2.txt, file3.txt, file4.txt ) con la cadena "Good Morning" utilizando un comando de terminal único.

Todos los archivos de texto se encuentran en mi ~/Desktop.

Nota: Mi escritorio consta de 6 archivos .txt. Deseo aplicar el cambio solo a los 4 archivos de texto mencionados anteriormente.

Avinash Raj
fuente

Respuestas:

40

Aquí hay algunos enfoques. Estoy usando la expansión de llaves ( file{1..4}.txt) lo que significafile1.txt file2.txt file3.txt file4.txt

  1. Perl

    perl -i -pe 's/.*/ Good Morning / if $.==5' file{1..4}.txt

    Explicación:

    • -i: hace perlque los archivos se editen en su lugar, cambiando el archivo original.

      Si -ise sigue con un sufijo de extensión de archivo, se crea una copia de seguridad para cada archivo que se modifica. Ej: -i.bakcrea un file1.txt.bakif file1.txtmodificado durante la ejecución.

    • -p: significa leer el archivo de entrada línea por línea, aplicar el script e imprimirlo.

    • -e: le permite pasar un script desde la línea de comando.

    • s/.*/ Good Morning /: Eso reemplazará el texto en la línea actual ( .*) con Buenos días.

    • $.es una variable especial de Perl que contiene el número de línea actual del archivo de entrada. Entonces, s/foo/bar/ if $.==5significa reemplazar foocon barsolo en la quinta línea.

  2. sed

    sed -i '5s/.*/ Good Morning /' file{1..4}.txt

    Explicación:

    • -i: Me gusta para perl, editar archivo en su lugar.

    Por defecto, sedimprime cada línea del archivo de entrada. El 5s/pattern/replacement/patrón de sustitución de medios con reemplazo en la quinta línea

  3. Awk

    for f in file{1..4}.txt; do 
        awk 'NR==5{$0=" Good Morning "}1;' "$f" > foobar && mv foobar "$f"; 
    done

    Explicación:

    awkno tiene equivalente a la -iopción¹, lo que significa que necesitamos crear un archivo temporal ( foobar) que luego se renombra para sobrescribir el original. El ciclo bash for f in file{1..4}.txt; do ... ; donesimplemente pasa por cada uno de ellos file{1..4}.txt, guardando el nombre del archivo actual como $f. En awk, NRes el número de línea actual y $0es el contenido de la línea actual. Entonces, el script reemplazará la línea ( $0) con "Buenos días" solo en la 5ta línea. 1;es awkpara "imprimir la línea".

    ¹ Las nuevas versiones no tan devnull mostraron en su respuesta .

  4. coreutils

    for f in file{1..4}.txt; do 
        (head -4 "$f"; echo " Good Morning "; tail -n +6 "$f") > foobar && 
        mv foobar "$f"; 
    done 

    Explicación:

    El ciclo se explica en la sección anterior.

    • head -4: imprime las primeras 4 líneas

    • echo " Good Morning ": imprimir "Buenos días"

    • tail -n +6: imprime todo, desde la sexta línea hasta el final del archivo

    Los paréntesis ( )alrededor de esos tres comandos le permiten capturar la salida de los tres (por lo tanto, primero 4 líneas, luego "Buenos días", luego el resto de las líneas) y redirigirlos a un archivo.

terdon
fuente
23

Podrías usar sed:

sed '5s/^/Good morning /' file

se agregaría Good morningen la quinta línea de un archivo.

Si desea reemplazar los contenidos en la línea 5, diga:

sed '5s/.*/Good morning/' file

Si desea guardar los cambios en el archivo en el lugar, use la -iopción:

sed -i '5s/.*/Good morning/' file

sedpuede manejar más de un archivo a la vez. Simplemente puede agregar más nombres de archivo al final del comando. También puede usar expansiones bash para unir archivos particulares:

# manually specified
sed -i '5s/.*/Good morning/' file1.txt file2.txt file3.txt file4.txt

# wildcard: all files on the desktop
sed -i '5s/.*/Good morning/' ~/Desktop/*

# brace expansion: file1.txt, file2.txt, file3.txt, file4.txt
sed -i '5s/.*/Good morning/' file{1..4}.txt

Puede leer más sobre expansiones de llaves aquí .


Las versiones de GNU awk 4.1.0 y superiores vienen con una extensión que permite la edición en el lugar. Entonces podrías decir:

gawk -i inplace 'NR==5{$0="Good morning"}7' file

para reemplazar la línea # 5 en el archivo con Good morning!

devnull
fuente
2

No vi la solución de Python, así que aquí está:

import sys
import os
def open_and_replace(filename):

    with open(filename) as read_file:
        temp = open("/tmp/temp.txt","w")
        for index,line in enumerate(read_file,1):
            if  index == 5:
                temp.write("NEW STRING\n")
            else:
                temp.write(line.strip() + "\n")
        temp.close()
    os.rename("/tmp/temp.txt",filename)

for file_name in sys.argv[1:]:
    open_and_replace(file_name)

La idea básica es que para cada archivo proporcionado en la línea de comandos como argumento, escribimos un archivo temporal y enumeramos cada línea en el archivo original. Si el índice de la línea es 5, escribimos una línea diferente. El resto solo reemplaza el archivo antiguo con el archivo temporal Demo:

$> ls
file1.txt  file2.txt  file3.txt
$> cat file1.txt                                                               
line 1
line 2
line 3
line 4
GOOD MORNING
line 6
$> python ~/replace_5th_line.py file1.txt file2.txt  file3.txt                 
$> cat file1.txt                                                               
line 1
line 2
line 3
line 4
NEW STRING
line 6
$> cat file2.txt                                                               
line 1
line 2
line 3
line 4
NEW STRING
line 6

Lo mismo se puede lograr con la comprensión de la lista. A continuación se muestra una línea del mismo guión:

cat /etc/passwd | python -c 'import sys; print "\n".join(["CUSTOM"  if index == 5 else line.strip() for index,line in enumerate(sys.stdin,1)])'

o sin cat

python -c 'import sys; print "\n".join(["CUSTOM"  if index == 5 else line.strip() for index,line in enumerate(sys.stdin,1)])' < /etc/passwd

Lo que queda es simplemente redirigir la salida del contenido editado a otro archivo con > output.txt

Sergiy Kolodyazhnyy
fuente
1

Puede usar Vim en modo Ex:

for b in 1 2 3 4
do
  ex -sc '5c|Good Morning' -cx file"$b".txt
done
  1. 5 seleccione 5ta línea

  2. c reemplazar texto

  3. x escriba si se han realizado cambios (lo han hecho) y salga

Steven Penny
fuente
0

El siguiente es un script bash que resume el proceso de perl sugerido en esta respuesta

Ejemplo:

/ tmp / it

console:
  enabled:false

Luego ejecute lo siguiente:

$ search_and_replace_on_line_of_file.sh false true 2 /tmp/it

y el archivo ahora contiene

/ tmp / it

console:
  enabled:true

search_and_replace_on_line_of_file.sh

function show_help()
{
  IT=$(CAT <<EOF

  usage: SEARCH REPLACE LINE_NUM FILE

  e.g. 

  false true 52 /tmp/it  -> replaces false with true on line 52 of file /tmp/it

  )
  echo "$IT"
  exit
}

if [ "$1" == "help" ]
then
  show_help
fi
if [ -z "$4" ]
then
  show_help
fi

SEARCH_FOR=$1
REPLACE_WITH=$2
LINE_NO=$3
FILE_NAME=$4
perl -i -pe "s/$SEARCH_FOR/$REPLACE_WITH/ if $.==$LINE_NO" $FILE_NAME 
parques brad
fuente