Como imprimo tudo, exceto a décima a última linha no sed?

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

    sed 13q;d <file.txt
    

    De maneira mais geral, é possível fazer esse tipo de complemento / inverso / oposto sed? Ou apenas para regexes?

  • Como imprimo tudo, exceto a terceira à última linha? Isso requer dois tace contando para a frente sed? Ou existe uma maneira sedde contar pela parte de trás?

isomorfismos
fonte

Respostas:

12

Parte 1

Simplesmente delimine a 13ª linha:

sed '13d' <file.txt

E uma maneira geral de fazer o complemento 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 necessário. Então, se você quisesse a última linha 10, seria 11.

Testando 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 

A valiosa adição 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 \nsequência pode não funcionar com outros seds.


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

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

Portanto, esta é uma tentativa de uma versão mais independente da 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.

Trauma Digital
fonte
@jimmij As outras respostas sobre questões relacionadas na rede SE sugerem que uma solução head/ tailé muito mais lenta que uma sedsolução. Obrigado embora.
Isomorphismes
3
@ isomorphismes nenhum programa pode saber o número de linhas em um arquivo, a menos que ele passe por todo o arquivo. Não há maneira de contornar isso. A única maneira de contar da parte inferior é reverter o arquivo e contar da parte superior ou analisá-lo duas vezes. Então, cabeça / cauda será o mais rápido possível.
terdon
@ isomorphismes ... porque eles ( head/ tail) são otimizados para fazer o que fazem.
Peterph
@isomorphismes - editado com todas as peças que você precisa
Digital Trauma
Agradável! Eu tive que mudar minha resposta, já que de alguma forma esperava que fosse mais complicado. :)
peterph