![Sed substitui apenas em linhas pares de um arquivo quando comandos de substituição são escritos em um arquivo](https://rvso.com/image/1416716/Sed%20substitui%20apenas%20em%20linhas%20pares%20de%20um%20arquivo%20quando%20comandos%20de%20substitui%C3%A7%C3%A3o%20s%C3%A3o%20escritos%20em%20um%20arquivo.png)
Eu tenho todos os comandos de substituição em um arquivo (digamos replace.sed) e os uso com o sinalizador -f do sed (sed -f replace.sed InputFile). Mas agora me deparei com uma condição em que preciso aplicar essas regras de substituição apenas em linhas pares de um determinado arquivo de entrada (ou seja, apenas na linha 2,4,6 e assim por diante). .sed, pois também é usado por outros scripts.
Responder1
Use a substituição de processo para adaptar os sed
comandos em seu arquivo dinamicamente:
$ cat replace.sed
s#foo#bar#
.
$ printf "foo\nfoo\nfoo\nfoo\n" | sed -f replace.sed
bar
bar
bar
bar
.
$ printf "foo\nfoo\nfoo\nfoo\n" | sed -f <(sed 's#^#2~2#g' replace.sed)
foo
bar
foo
bar
Responder2
sed -f <(sed -e 's/.*/2~2{&;}/' replace.sed) InputFile
Responder3
O que as outras respostas estão dizendo é que você deve usar o formulário de endereço sed
de :first~step
Endereços
… Os seguintes tipos de endereço são suportados:…
primeiro~etapaCombine todosetapa'ª linha começando com linhaprimeiro. Por exemplo, “
sed -n 1~2p
” imprimirá todas as linhas ímpares no fluxo de entrada e o endereço “2~5
” corresponderá a cada quinta linha, começando pela segunda. primeiropode ser zero; neste caso,sed
opera como se fosse igual a etapa. (Esta é uma extensão.)
A solução óbvia seria preceder cada comando replace.sed
com 2~2
(ou 0~2
, se funcionar na sua versão de sed
) para fazer os comandos operarem em linhas alternadas, começando com a segunda (ou seja, todas as linhas pares no fluxo de entrada, como você pediu). Mas você diz que não pode modificar replace.sed
. Bem, o próximo passo (conforme identificado, mas não explicado, pelas outras respostas) é criar um arquivo temporário temporário com o shellSubstituição de Processocapacidade, onde atua como um arquivo que é a saída de . Se, como sua pergunta sugere, for apenas uma sequência de comandos substitutos simples, então
<(command_list)
command_list
replace.sed
sed -f <(sed 's/^/2~2/g' replace.sed)
Deveria trabalhar.
Mas isso tem desvantagens:
- Se você tiver vários comandos por linha, o procedimento acima afetará apenas o primeiro comando de cada linha.
- Se você tiver comandos com endereços numéricos (por exemplo,
42s/Zaphod/Beeblebrox/
), eles serão convertidos, por exemplo, em2~242…
, com a consequência óbvia. - E se você tiver comandos com endereços não numéricos (por exemplo,
/windows/s/command/cmd/
), o acima irá falhar completamente.
Se algum desses casos se aplicar, você deve usar o
sed -f <(sed -e 's/.*/2~2{&;}/' replace.sed)
variação para colocar todos os sed
comandos em cada linha em um grupo de comandos.
Mas mesmo isso falhará se replace.sed
tiver comandos multilinhas.
Com base nas ideias acima, criei
sed -f <(echo '0~2{'; cat replace.sed; echo '}')
o que coloca ointeiro replace.sed
arquivo em um grupo de comandos. Nos meus testes superficiais, isso parece resolver as preocupações que levantei com as outras soluções. Eu não ficaria chocado se houvesse um problema com replace.sed
comandos muito longos ou muito complexos.