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< file2
abrefile2
para ler no descritor de arquivo 3. - O
grep -n
encontra as linhas emfile1
que 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 junk
significa 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 <&3
lê 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
. -
… || break
diz, se oread
acima falhar (presumivelmente devido ao final do arquivo), sair do loop. - O comando
printf
escreve um comandosed
c 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 ciclowhile
e 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
while
termina assim que recebe um EOF de qualquer entrada. Portanto, sefile1
tiver maistid.setnr
linhas quefile2
, os extras ficarão inalterados (isto é, os comandosc
para eles não serão gerados). Da mesma forma, sefile2
tiver maistid.setnr
linhas 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_file1
corresed
emfile1
, lendo comandos de$tmpfile
e 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
--lines
até descobrir o que é o máximo. -
Tente
sed -f xaa -f xab -f xac -f xad -f xae -f xaf file1 > modified_file1_test
mas 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"*