Como imprimo todos, exceto a enésima a última linha em sed?

9
  • Eu gostaria de fazer o complemento / "oposto" de

    sed 13q;d <file.txt
    

    Mais geralmente, é possível fazer esse tipo de complemento / inverso / oposto em sed ? Ou apenas para regexes?

  • Como imprimo todos, exceto a terceira à última linha? Isso requer dois tac e conta em frente em sed ? Ou há um caminho obter o sed para contar na parte de trás?

por isomorphismes 25.09.2014 / 22:08

1 resposta

12

Parte 1

Simplesmente d elete a 13ª linha:

sed '13d' <file.txt

E uma maneira geral de fazer o complemento dos itens acima é:

sed '13!d' <file.txt

Parte 2

Porque isso pode ser feito:

sed -n ':a;${P;q};N;4,$D;ba' <file.txt

Observe que 4 é um a mais que o número desejado. Então, se você quisesse a última 10ª linha, isso seria 11 .

Teste com seq :

$ seq 100 | sed -n ':a;${P;q};N;4,$D;ba'
98
$ 

Tentativa de explicação

:a        # define label a
${        # match the last line
    P     # print the first line of the pattern space
    q     # quit
}
N         # match all lines: append the next line to the pattern
4,${      # match the range of lines 4 to the end of the file
    D     # delete the first line of the pattern space
}
ba        # match all lines: jump back to label a 

Adição valiosa de Glenn Jackman:

Essa foi "apenas a enésima linha". Aqui está "tudo, MAS a enésima linha":

sed -n ':a;${s/^[^\n]*\n//;p;q};N;4,${P;D};ba'

funciona com o GNU sed, a sequência \n pode não funcionar com outros seds.

Eu tentei isso com o BSD sed (OSX) e achei que não funcionava bem na forma acima. Os problemas parecem ser:

  1. ; usado para separar linhas parece funcionar geralmente, mas não funciona depois de um rótulo
  2. O BSD sed parece exigir ; após o último comando em um grupo de comando {} de uma linha, enquanto o sed GNU não
  3. \n geralmente pode ser usado dentro da expressão regular, mas aparentemente não dentro de uma expressão de parêntese [] . Então, para excluir novas linhas, podemos usar algo como [[:alnum:][:punct:][:graph:][:blank:]] , embora isso possa excluir outros caracteres (especificamente outros caracteres de controle).

Portanto, esta é uma tentativa de uma versão independente de plataforma:

sed -n ':a
${s/^[[:alnum:][:punct:][:graph:][:blank:]]*\n//p;q;};N;4,${P;D;};ba'

Isso parece funcionar no OSX e no Ubuntu.

    
por 25.09.2014 / 22:18