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

3

Eu tenho todos os comandos replace em um arquivo (digamos replace.sed) e eu uso-o com o flag -f de sed (sed -f replace.sed InputFile). Mas agora eu corri para uma condição onde eu preciso aplicar estas regras de substituição apenas em linhas numeradas pares de um determinado arquivo de entrada (ou seja, apenas na linha não 2,4,6 e assim por diante) .Eu não posso colocar quaisquer instruções de condição em substituir arquivo .sed como isso é usado por outros scripts também.

    
por Abhishek 24.07.2014 / 10:24

3 respostas

1

Use a substituição de processo para adaptar os comandos sed em seu arquivo em tempo real:

$ 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
    
por 24.07.2014 / 10:35
1
sed -f <(sed -e 's/.*/2~2{&;}/' replace.sed) InputFile
    
por 24.07.2014 / 18:52
1

Quais são as outras respostas dizendo a você tentando lhe dizer é usar o formulário de endereço sed first~step :

Addresses

    …    The following address types are supported:   …

    first~step
      Match every step’th line starting with line first.  For example,  “sed -n 1~2p”  will print all the odd-numbered lines in the input stream, and the address  “2~5”  will match every fifth line, starting with the second.  first can be zero; in this case, sed operates as if it were equal to step.  (This is an extension.)

A solução óbvia seria preceder todos os comandos em replace.sed com 2~2 (ou 0~2 , se funciona na sua versão de sed ) para fazer com que os comandos operem em todas as outras linhas, começando com o segundo (ou seja, todas as linhas pares no fluxo de entrada, conforme solicitado). Mas você diz que não pode modificar replace.sed . Bem, o próximo passo (como identificado, mas não explicado, pelas outras respostas) é para criar um arquivo temporário temporário com o recurso Processo de Substituição do shell, onde <(command_list) age como um arquivo que é a saída de command_list . Se, como sua pergunta sugere, replace.sed é apenas uma sequência de comandos substitutos simples, então

sed -f <(sed 's/^/2~2/g' replace.sed)

deve funcionar.

Mas isso tem desvantagens:

  • Se você tiver vários comandos por linha, então o acima afetará apenas o primeiro comando em 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 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 comandos sed em cada linha em um grupo de comandos.

Mas mesmo isso falhará se replace.sed tiver comandos de várias linhas.

Com base nas ideias acima, criei

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

que coloca o arquivo inteiro replace.sed 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 tivesse um problema com um replace.sed muito longo, ou com comandos muito complexos.

    
por 24.07.2014 / 21:44