batch find / replace usando sed ou awk

1

Em todos os arquivos com nome de arquivo compatível com pattern1, quero procurar por linhas que comecem com pattern2 e adicionar algumas strings em uma nova linha acima dessas linhas correspondentes.

Como um exemplo simples, suponha que eu esteja procurando recursivamente em arquivos .txt para potato e quero adicionar 'spam' acima, então o arquivo /tmp/blah.txt

hello
potato
world
not potato
bye

seria transformado em

hello
spam
potato
world
not potato
bye

Parece um trabalho simples para um assistente de shell, qual é a maneira mais fácil de conseguir isso? Eu marquei algumas das ferramentas que acho que seriam os suspeitos usuais aqui, mas estou aberto a outras sugestões. Pontos de bônus, se ele pode me mostrar um diff de pré-visualização antes de confirmar a modificação dos arquivos no lugar.

    
por wim 03.01.2014 / 12:37

2 respostas

2

Eu também faria isso em Perl:

$ for f in *txt; do perl -pne 'print "spam\n" if /^potato/' "$f"; done
hello
spam
potato
world
spam
not potato
bye

O -p flag faz com que o perl imprima cada linha do arquivo de entrada. O -n significa "leia o arquivo de entrada linha por linha" e aplique o script fornecido por -e em cada linha. Em seguida, o próprio script imprimirá spam se a linha atual contiver potato e imprimirá cada linha. O resultado será a string spam impressa acima das linhas contendo potato .

Isso simplesmente imprimirá o novo arquivo sem modificá-lo. Se você quiser fazer as alterações no arquivo original, use -i :

$ for f in *txt; do perl -i.bak -pne 'print "spam\n" if /^potato/' "$f"; done

Isso criará um arquivo de backup chamado foo.txt.bak para cada arquivo processado e aplicará as alterações a foo.txt .

    
por 03.01.2014 / 14:18
2

Pessoalmente, eu provavelmente usaria o perl para algo assim, mas você pode conseguir o que deseja no bash:

while read -r line ; do if [[ $line =~ "potato" ]]; then echo spam;  fi;  echo $line; done < file.txt

Se você quiser colocar o resultado em um novo arquivo:

while read -r line ; do if [[ $line =~ "potato" ]]; then echo spam;  fi;  echo $line; done < file.txt > /tmp/outfile.txt
    
por 03.01.2014 / 13:42