Como substituir uma string na quinta linha de vários arquivos de texto?

21

Eu quero substituir a quinta linha de vários arquivos de texto ( arquivo1.txt, arquivo2.txt, arquivo3.txt, arquivo4.txt ) com a string "Good Morning" usando um único comando de terminal .

Todos os arquivos de texto estão localizados no meu ~/Desktop .

Observação: minha área de trabalho consiste em 6 arquivos .txt. Quero aplicar a alteração apenas nos 4 arquivos de texto mencionados acima.

    
por Avinash Raj 14.03.2014 / 06:47

5 respostas

38

Aqui estão algumas abordagens. Estou usando a expansão de chaves ( file{1..4}.txt ), o que significa file1.txt file2.txt file3.txt file4.txt

  1. Perl

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

    Explicação:

    • -i : faz com que perl edite os arquivos no lugar, alterando o arquivo original.

      Se -i for seguido com um sufixo de extensão de arquivo, um backup será criado para cada arquivo modificado. Ex: -i.bak cria um file1.txt.bak se file1.txt for modificado durante a execução.

    • -p : significa ler o arquivo de entrada linha a linha, aplicar o script e imprimi-lo.

    • -e : permite que você passe um script da linha de comando.

    • s/.*/ Good Morning / : Isso substituirá o texto da linha atual ( .* ) pelo bom dia.

    • $. é uma variável Perl especial que contém o número da linha atual do arquivo de entrada. Portanto, s/foo/bar/ if $.==5 , significa substituir foo por bar apenas na quinta linha.

  2. sed

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

    Explicação:

    • -i : como para perl , edite o arquivo no lugar.

    Por padrão, sed imprime cada linha do arquivo de entrada. O 5s/pattern/replacement/ significa padrão substituto com substituição na quinta linha.

  3. Awk

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

    Explicação:

    awk não tem equivalente à -i option¹, o que significa que precisamos criar um arquivo temporário ( foobar ) que será renomeado para substituir o original. O laço bash for f in file{1..4}.txt; do ... ; done simplesmente passa por cada file{1..4}.txt , salvando o nome do arquivo atual como $f . Em awk , NR é o número da linha atual e $0 é o conteúdo da linha atual. Assim, o script substituirá a linha ( $0 ) por "Bom dia" somente na quinta linha. 1; é awk para "imprimir a linha".

    ¹ As versões mais recentes são mostradas como devnull em sua resposta .

  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 
    

    Explicação:

    O loop é explicado na seção anterior.

    • head -4 : imprima as primeiras 4 linhas

    • echo " Good Morning " : print "Bom dia"

    • tail -n +6 : imprima tudo da sexta linha até o final do arquivo

    Os parênteses ( ) em torno desses três comandos permitem capturar a saída de todos os três (assim, as primeiras 4 linhas, depois "bom dia" e depois o restante das linhas) e redirecioná-las para um arquivo.

por terdon 14.03.2014 / 06:59
22

Você pode usar sed :

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

acrescentaria Good morning na quinta linha de um arquivo.

Se você quiser substituir o conteúdo na linha 5, diga:

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

Se você quiser salvar as alterações no arquivo no local, use a opção -i :

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

sed pode manipular mais de um arquivo por vez. Você pode simplesmente adicionar mais nomes de arquivo ao final do comando. Você também pode usar expansões bash para corresponder a arquivos específicos:

# 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

Você pode ler mais sobre as expansões de chaves aqui .

As versões do GNU awk 4.1.0 e superior vêm com uma extensão que permitem a edição no local. Então você poderia dizer:

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

para substituir a linha 5 no arquivo com Good morning !

    
por devnull 14.03.2014 / 06:53
2

Eu não vi a solução python, então aqui 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)

A ideia básica é que para cada arquivo fornecido na linha de comando como argumento, escrevemos um arquivo temporário e enumeramos cada linha no arquivo original. Se o índice da linha é 5, nós escrevemos a linha que é diferente. O resto está apenas substituindo o arquivo antigo pelo arquivo temporário Demonstração:

$> 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

O mesmo pode ser alcançado com a compreensão da lista. Abaixo está um verso do mesmo script:

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)])'

ou sem 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

O que resta é simplesmente redirecionar a saída do conteúdo editado para outro arquivo com > output.txt

    
por Sergiy Kolodyazhnyy 08.08.2016 / 21:21
1

Você pode usar o Vim no modo Ex:

for b in 1 2 3 4
do
  ex -sc '5c|Good Morning' -cx file"$b".txt
done
  1. 5 selecione a quinta linha

  2. c substituir texto

  3. x escreve se foram feitas alterações (elas foram) e sai

por Steven Penny 16.04.2016 / 17:18
0

O seguinte é um script bash que encerra o processo de perl sugerido nesta resposta

Exemplo:

/ tmp / it

console:
  enabled:false

Em seguida, execute o seguinte:

$ search_and_replace_on_line_of_file.sh false true 2 /tmp/it

e o arquivo agora contém

/ 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 
    
por brad parks 17.06.2016 / 16:20