Como executar uma substituição sed-in-place que apenas crie backups de arquivos que foram alterados?

13

Eu executei o seguinte para substituir um termo usado em todos os arquivos no diretório de trabalho atual:

$ find . -type f -print0 | xargs -0 sed -i'.bup' -e's/Ms. Johnson/Mrs. Melbin/g'

Isso executou a substituição de palavras, mas também criou .bup arquivos de arquivos que nunca tiveram a string Ms. Johnson .

Como faço a substituição sem criar todos esses backups desnecessários?

    
por Belmin Fernandez 21.11.2011 / 03:53

4 respostas

6

Você pode verificar o conteúdo dos arquivos para garantir que uma substituição ocorrerá quando sed operá-los:

find . \
    -type f \
    -exec grep -q 'Ms. Johnson' {} \; \
    -print0 |
xargs -0 sed -i'.bup' -e's/Ms. Johnson/Mrs. Melbin/g'

Se você quer ser realmente esperto, você pode renunciar a usar find :

grep -Z -l -r 'Ms. Johnson' |
    xargs -0 sed -i'.bup' -e's/Ms. Johnson/Mrs. Melbin/g'
    
por 21.11.2011 / 04:08
7

O Find tem um operador -exec que executa um comando arbitrário. Melhor ainda, -exec é um teste , então você pode encadear vários -exec s juntos, e se os comandos anteriores falharem, os posteriores não serão executados. A string {} é substituída pelo nome do arquivo atual e ; marca o final do comando. Você deve citar ambos para evitar que a concha interfira.

Então:

find . -type f \
    -exec grep -q 'Ms. Johnson' '{}' \; \
    -exec sed -i'.bup' -e's/Ms. Johnson/Mrs. Melbin/g' '{}' \;
    
por 21.11.2011 / 04:12
4

Eu olhei para a página man e não vi nenhuma maneira de fazer isso diretamente através de sed , como tenho certeza que você fez antes de perguntar. Eu vejo várias maneiras de contornar isso usando o grep, mas eu acho que o mais fácil é isso:

grep -rlZ "Ms. Johnson" . | xargs -0 sed -i'.bup' -e's/Ms. Johnson/Mrs. Melbin/g'

-r recurse
-l imprime nome do arquivo somente% -Z end nomes com nulo

    
por 21.11.2011 / 04:13
-1

Parece que você precisa criar uma lista de arquivos que correspondam aos seus termos de pesquisa primeiro.

search="test"
for match in $(find -type f -exec grep -l $search "{}" \;)
do sed -i'.bup' -e "/$search/ s/$search/Mrs. Melbin/g" "$match"
done
    
por 21.11.2011 / 04:10