Qual é o significado de: a; $! N; em um comando sed?

11
$ (echo hello; echo there) | sed ':a;$!N;s/\n/string/;ta'
hellostringthere

O sedcomando acima substitui o novo caractere de linha pela string "string". Mas não sei o significado das :a;$!N;s/\n/string/;taaspas simples. Eu sei a parte do meio s/\n/string/. Mas não sei a função da primeira ( :a;$!N;) e da última ( ta) parte.

Avinash Raj
fonte
2
consulte stackoverflow.com/questions/1251999/… .
Xiaodongjie
E a última parte?
Avinash Raj
O comando "t" ramifica para um rótulo nomeado se o último comando substituto modificou o espaço do padrão.
Xiaodongjie

Respostas:

17

Estes são os sedcomandos , reconhecidamente enigmáticos . Especificamente (de man sed):

: label
         Etiqueta para os comandos be t.

t label
         Se como /// fez uma substituição bem-sucedida desde que a última linha de entrada foi lida e desde o último comando t ou T, ramifique para label; se o rótulo for omitido, ramifique para o final do script.

n N Leia / anexe a próxima linha de entrada no espaço do padrão.

Portanto, o script que você postou pode ser dividido em (espaços adicionados para facilitar a leitura):

sed ':a;  $!N;  s/\n/string/;  ta'
     ---  ----  -------------  --
      |     |        |          |--> go back (`t`) to `a`
      |     |        |-------------> substitute newlines with `string`
      |     |----------------------> If this is not the last line (`$!`), append the 
      |                              next line to the pattern space.
      |----------------------------> Create the label `a`.

Basicamente, o que isso está fazendo pode ser escrito em pseudocódigo como

while (not end of line){
    append current line to this one and replace \n with 'string'
}

Você pode entender isso um pouco melhor com um exemplo de entrada mais complexo:

$ printf "line1\nline2\nline3\nline4\nline5\n" | sed ':a;$!N;s/\n/string/;ta'
line1stringline2stringline3stringline4stringline5

Não sei ao certo por que isso !$é necessário. Tanto quanto eu posso dizer, você pode obter a mesma saída com

printf "line1\nline2\nline3\nline4\nline5\n" | sed ':a;N;s/\n/string/;ta'
Terdon
fonte
1
O! $ É para não corresponder à última nova linha, IMO.
Braiam 5/05
@Braiam não muito certo sobre isso, é $!não !$. No entanto, também pode ser !Ne não $!.
terdon 5/05
Eu estava tentando analisar a página texinfo, mas não encontrei referências a nenhum !Nou a $!. Portanto, continuo pensando que a última linha é nova linha ou EOF.
Braiam 5/05
4
Eu tento pensar $!como um endereço 'range' com um operador de complemento postfix - assim $!N(em Nqualquer lugar, exceto no endereço $), é realmente a mesma sintaxe de algo como m,n!d(exclua tudo, exceto as linhas mpara n).
Steeldriver #
:é analógico de gotoetiqueta, e de fato :costumava ser Goto rótulo em Thompson shell, então seria familiar para as pessoas de volta ao dia usando tanto sed e Thompson shell
Sergiy Kolodyazhnyy
0

Eu postar esta resposta desde que eu vejo um monte de confusão sobre por que a última linha é excluído durante a execução N(através da linha de cadeia de endereçamento $!) e porque o OP estava confuso sobre o significado :a;$!N; em um comando sed , não só na a um específico ele postou .

Bem, o benefício de usar em $!Nvez de Nnão é evidente nos exemplos propostos (pelo OP e pelo @terdon), já que nenhum comando "importante" (continue lendo) é executado na última linha após o Ncomando. (De fato, o resultado é o mesmo se alguém retirar esse endereço da linha.)

Em um exemplo mais complexo (por exemplo, substitua this sentenceem um arquivo, com as duas palavras aparecendo algumas vezes em uma linha e outras vezes em duas linhas), excluir a última linha do Ncomando pode ser crucial! Se a última linha não for excluída, ao ser executada N, ela sedbate EOFe sai imediatamente, impedindo que todos os comandos subseqüentes (também os comandos de ramificação, ou seja, te b) sejam executados.

Nos exemplos simplistas mostrados, podemos remover com segurança $!e deixar de sedexecutar Ne retornar com falha, pois o scomando abortado não faria nada se fosse executado, pois não há \ncomo corresponder.

Enrico Maria De Angelis
fonte