Uma maneira de fazer isso com sed é gerar um script sed :
tmpfile=/tmp/Nainita.$$
exec 3< file2
grep -n "tid\.setnr" file1 | while IFS=: read n junk
do
IFS= read -r line <&3 || break
printf "%sc%s\n%s\n" "$n" '\' "$line"
done > "$tmpfile"
exec 3<&-
sed -f "$tmpfile" file1 > modified_file1
rm -f "$tmpfile"
-
exec 3< file2abrefile2para ler no descritor de arquivo 3. - O
grep -nencontra as linhas emfile1que contêmtid.setnr, por número de linha. Isso é canalizado em um loopwhile. -
while IFS=: read n junk-
while … read …significa ler uma linha por vez, repetidamente contanto que haja informações para ler (ou seja, parando quando chegar ao final dos dados). -
IFS=: read n junksignifica ler tudo até o primeiro:(que será o número da linha degrep -n) emn, e o resto da linha (a antiga linha de dadostid.setnr) emjunk, que ignoramos, porque não nos importamos com isso.
-
-
IFS= read -r line <&3lê uma linha do descritor de arquivo 3 (file2), fazendo tudo o que sabemos fazer para dizer ao shell para não rasgá-lo, e colocá-lo em uma variável chamadaline. -
… || breakdiz, se oreadacima falhar (presumivelmente devido ao final do arquivo), sair do loop. - O comando
printfescreve um comandosedc hange, endereçado para o número de linhan, dizendo que essa linha deve ser substituída com o conteúdo na variávelline. -
done > "$tmpfile"marca o final do ciclowhilee especifica que a saída padrão de todo o loop é$tmpfile. Isso terminará assim:13c\ #.tid.setnr := 1254 22c\ #.tid.setnr := 9056
- Observe que o loop
whiletermina assim que recebe um EOF de qualquer entrada. Portanto, sefile1tiver maistid.setnrlinhas quefile2, os extras ficarão inalterados (isto é, os comandoscpara eles não serão gerados). Da mesma forma, sefile2tiver maistid.setnrlinhas quefile1, os extras serão ignorados. Infelizmente, esta discrepância não será relatada, embora adicionar essa capacidade não seria muito difícil.
- Observe que o loop
-
exec 3<&-fecha o descritor de arquivo 3. -
sed -f "$tmpfile" file1 > modified_file1corresedemfile1, lendo comandos de$tmpfilee escrevendo saída paramodified_file1.
Isso deve fazer o que você quiser. Obviamente, mude os nomes dos arquivos, se quiser.
Você deve executar isso “como está” uma vez e, em seguida, examinar o arquivo modified_file1
(ou simplesmente altere o comando sed para não redirecionar sua saída,
por isso, escreve na tela) e verifique se a saída é o que você deseja.
Em seguida, você pode alterar o comando sed para sed -i para editar file1 no lugar
(se é isso que você quer fazer).
Se o comando sed der um erro como "Número excessivo de linhas",
tente dividir o arquivo de script ( $tmpfile ) em arquivos menores.
Eu sugiro começar com um tamanho abaixo de 100 comandos;
por exemplo, 90 comandos, que são 180 linhas, pois cada comando é de duas linhas.
Você pode fazer isso manualmente, com um editor de texto 1 ,
mas há uma ferramenta escrita especificamente para este trabalho.
É, intuitivamente, chamado split . O comando
split --lines=180 "$tmpfile"
dividirá o script em arquivos no diretório atual
chamado xaa , xab , xac ,…. O primeiro n −1 terá 180 linhas de comprimento;
o último será o que for necessário (≤ 180) para perfazer o total.
Por exemplo, se você tiver 500 instâncias de tid.setnr ,
então o seu script terá 1000 linhas de comprimento e você terá 6% de arquivosx -
xaa , xab , xac , xad e xae terão 180 linhas,
e xaf terá 100. Agora, faça
sed -f xaa file1 > modified_file1aa
Se você ainda tiver "muitos números de linha",
volte e tente novamente com um número menor de --lines .
Se ele não informar um erro, veja modified_file1aa e veja
se parece que as primeiras 90% das linhastid.setnr foram alteradas.
Se parece OK, então faça
sed -f xab modified_file1aa > modified_file1ab
sed -f xac modified_file1ab > modified_file1ac
sed -f xad modified_file1ac > modified_file1ad
sed -f xae modified_file1ad > modified_file1ae
sed -f xaf modified_file1ae > modified_file1af
modified_file1af agora é seu% finalmodified_file1.
Se você quiser experimentar play , você pode
- Tente números maiores de
--linesaté descobrir o que é o máximo. -
Tente
sed -f xaa -f xab -f xac -f xad -f xae -f xaf file1 > modified_file1_testmas isso provavelmente não funcionará.
- Se você fizer as experiências acima, incentive você a nos informar os resultados.
Se você só precisa fazer isso uma vez, está feito. Mas, se você precisar fazer isso repetidamente, altere as duas últimas linhas do bloco de código no topo desta resposta para
split --lines=180 "$tmpfile" <--- (Using a number that works for you, of course)
cp file1 modified_file1
for f in x*
do
sed -i -f "$f" modified_file1
done
rm -f "$tmpfile" x*
Como mencionei anteriormente,
a opção -i informa sed para editar o arquivo especificado no lugar
(ou seja, escreva as alterações de volta no arquivo de entrada). Ou, ainda mais simples,
split --lines=180 "$tmpfile"
for f in x*
do
sed -i -f "$f" file1
done
rm -f "$tmpfile" x*
se você não precisar manter o original file1 intacto.
Observe que a sinopse de uso para split é
split [OPTION]… [INPUT [PREFIX]]
e seu comportamento padrão é criar arquivos chamados PREFIXaa , PREFIXab , PREFIXac etc.
Em outras palavras, o padrão PREFIX é x .
Se você tiver outros arquivos cujos nomes começam com x ,
você deve definir prefix para ser algo que será único
(por exemplo, prefix=Nainita.$$. ou prefix=/tmp/Nainita.$$. )
e depois mude o acima para
split --lines=180 "$tmpfile" "$prefix"
for f in "$prefix"*
do
sed -i -f "$f" file1
done
rm -f "$tmpfile" "$prefix"*