Qual é a diferença entre os comandos sed 'n' e 'b'?

5

Além do ponto sintático óbvio, b pode aceitar um rótulo, enquanto n não aceita, e que, para usar b sem um rótulo, você precisa colocá-lo no final de um argumento passado com -e (para one-liners, pelo menos) ... um b sem um rótulo e um n parecem fazer exatamente a mesma coisa.

Isso é realmente verdade ou existem diferenças sutis que eu não notei? Quais são as condições sob as quais eles fazem a mesma coisa e as condições sob as quais não fazem?

    
por Wildcard 07.07.2016 / 22:59

3 respostas

4

Bem, vamos ver ...
o comando b ranch:

[2addr]b[label]
    Branch to :label. If label is not specified, branch to the end of the script.

o comando n ext:

[2addr]n
    If auto-print is not disabled, print the pattern space, then, regardless,
    replace the pattern space with the next line of input. If no next line of
    input is available, branch to the end of the script.

Então a principal diferença aqui é:

b ramifica-se incondicionalmente no final do script
n apenas ramifica para o final do script se não houver mais entrada

Assumindo uma entrada como:

fdue
four
four
fdue
four

e que eu queria substituir f por t , mas apenas em linhas que correspondem a four e em todas as outras linhas, substitua u por i . Uma maneira de fazer isso é

sed '/four/{s/f/t/;b;};s/u/i/' infile

e a saída é, como esperado

fdie
tour
tour
fdie
tour

agora, vamos ver o que acontece quando usamos n em vez de b :

fdie
tour
foir
fdie
tour

A segunda linha correspondente a four foi editada para foir em vez de tour pelo simples motivo n não retornar ao topo do script. Em vez disso, o comando s após o n processou a linha, mesmo que isso não fosse intencional. No entanto, na última linha, somente a primeira substituição foi feita, então o comando s depois que o n não foi mais executado.

Para resumir, esses dois comandos podem ser funcionalmente equivalentes se:

  • o script estava processando a última linha de entrada ( antes executando n ) ou
  • a próxima linha puxada por n não deveria ser editada pelos comandos que precedem n 1 de qualquer maneira (em outras palavras, a próxima linha não era um endereço associado a b )

É verdade que n imprime o espaço padrão atual e puxa a próxima linha, mas b sozinho também tem o mesmo efeito: ramificar para o final do script significa impressão automática (a menos que sed tenha sido invocado com -n , caso em que n também não imprime) e depois lendo automaticamente na próxima linha de entrada. A principal diferença, como eu disse, é que n não pula para o final do script (e ele também não retorna ao topo do script): sed simplesmente executa os comandos restantes - se houver ( e se não estiver na última linha ).

1
Esses comandos não serão executados, pois, como eu disse, n não retorna ao topo do script; Além disso, os demais comandos podem editar a linha que é algo que não deveria acontecer.

    
por 07.07.2016 / 23:24
6

Estes dois exemplos são os mesmos, exceto que n foi substituído por b . Você pode ver que a saída é diferente:

$ echo $'1\n2\n3' | sed 's/./AA/; n; s/./BB/'
AA
BB
AA
$ echo $'1\n2\n3' | sed 's/./AA/; b; s/./BB/'
AA
AA
AA

b ramifica para o final dos comandos. n continua com os comandos restantes. Assim, com b , a substituição s/./BB/ nunca é executada. Com n , é executado para todas as outras linhas.

(Os comandos acima foram executados usando o GNU sed. Com o BSD / OSX sed, como observa o OP, algumas pequenas alterações no formato do código seriam necessárias.)

    
por 07.07.2016 / 23:14
3

O comando "branch" ( b ) ramifica para um rótulo predefinido no script de edição ou para o final do script, se não houver rótulo, enquanto o comando "next" ( n ) lê a próxima linha de entrada. O comando "next" também gera o espaço padrão atual (geralmente a linha acabou de ler) antes de ler a próxima linha, a menos que a saída tenha sido suprimida com -n .

Eles são dois comandos de edição diferentes que fazem duas coisas diferentes. O comando "next" não causa um desvio para o final do script e o comando "branch" não produz o espaço padrão atual nem lê qualquer nova linha por si só.

Um exemplo simples (usando o GNU sed ):

$ cat lines
1
2
3
4
5

$ gsed -n '3{n;p;p;}' lines
4
4

O script irá, para a terceira linha, ler a próxima linha e imprimi-la duas vezes: A quarta linha é impressa duas vezes.

$ gsed -n '3{b;p;p;}' lines

Isso não gerará nenhuma saída porque o script irá ramificar além dos comandos "print" ( p ).

Correndo sem -n :

$ gsed '3{n;p;p;}' lines
1
2
3
4
4
4
5

A terceira linha é gerada pelo comando n no script. A quarta linha é gerada três vezes, duas vezes pelos dois p no script depois que n leu a próxima linha e uma vez pelo comando p padrão.

$ gsed '3{b;p;p;}' lines
1
2
3
4
5

As linhas são todas enviadas pelo comando p padrão, pois o comando "branch" irá ignorar os dois p no script.

Para resumir : n carrega a próxima linha e continua o processamento com a próxima instrução, enquanto b pula para a ramificação nomeada (se nomeada) ou para o final da linha roteiro. Em ambos os casos, quando o sed chega ao final do script, qualquer entrada restante é processada desde o início do script, como de costume.

    
por 07.07.2016 / 23:14

Tags