Tenho uma lista de arquivos e números de linha correspondentes onde desejo realizar a substituição:
s/LOG.error/LOG.warn
Existem outros lugares onde isso pode ocorrer e não quero perturbar essas linhas. Como posso fazer isso usando find e sed?
O arquivo está formatado como:
FooBar.java 125
FooBar.java 180
FooBar2.java 128
Isto é o que descobri enquanto procurava uma maneira de fazer isso:
cat filenames.txt | xargs sed -i '<get-line-number-here>s/LOG.error/LOG.warn' <get-file-name-here>
Responder1
Você precisará dividir o arquivo em partições por arquivo de destino e executar sed -i
cada arquivo individualmente. Supondo que você tenha os nomes dos arquivos e números de linha agrupados por nome de arquivo e em ordem crescente, você pode fazer algo como
awk '$1 != prev { if (prev) print "\047 " prev;
prev=$1;
printf "sed -i \047" }
{ print $2 "s/LOG\\.error/LOG.warn/" }
END { if (prev) print "\047 " prev }' filenames.txt | sh
Este é um hack rápido e sujo que irá quebrar de maneiras interessantes e possivelmente perigosas se os nomes dos arquivos na primeira coluna não forem um único token.
Basicamente, refatoramos seu arquivo de texto em uma sequência de sed
scripts. Então seu exemplo será transformado em
sed -i '125s/LOG\.error/LOG.warn
180s/LOG\.error/LOG.warn/
' FooBar.java
sed -i '128s/LOG\.error/LOG.warn/
' FooBar2.java
que você notará é um sh
script que contém um sed
script para cada arquivo.
Se você estiver em uma plataforma *BSD (incluindo Mac OS), você precisará alterar sed -i
o sed -i ''
que seria no Awk "sed -i \047\047"
para incorporar corretamente aspas simples sem perturbar as aspas do shell ao redor (para que a linha inteira se torne printf "sed -i \047\047 \047" }
(sic)).