Sed substitui apenas em linhas pares de um arquivo quando comandos de substituição são escritos em um arquivo

Sed substitui apenas em linhas pares de um arquivo quando comandos de substituição são escritos em um arquivo

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 sedcomandos 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 sedde :first~step

Endereços

    … Os seguintes tipos de endereço são suportados:…

    primeiro~etapa
      Combine 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, sedopera como se fosse igual a etapa. (Esta é uma extensão.)

A solução óbvia seria preceder cada comando replace.sedcom 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_listreplace.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, em 2~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 sedcomandos em cada linha em um grupo de comandos.

Mas mesmo isso falhará se replace.sedtiver comandos multilinhas.

Com base nas ideias acima, criei

sed -f <(echo '0~2{'; cat replace.sed; echo '}')

o que coloca ointeiro replace.sedarquivo 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.sedcomandos muito longos ou muito complexos.

informação relacionada