Oposto da cauda: todas as linhas, exceto as últimas n linhas

29

Como posso descartar as últimas n linhas de um arquivo com um filtro de linha de comando unix?

Isso seria uma espécie de oposto de tail: tail descarta as primeiras n linhas, mas canaliza o resto, mas eu quero que o comando canalize tudo exceto as últimas n linhas.

Infelizmente não encontrei nada assim - head não ajuda também. EDITAR : Pelo menos no Solaris ele não aceita argumentos negativos.

Atualização: estou mais interessado em uma solução que funciona para arquivos grandes, ou seja, arquivos de log, onde você pode querer inspecionar o que aconteceu nos últimos minutos.

Hans-Peter Störr
fonte
FYI ao usar a cabeça: Ao colocar ‘-’ na frente do número com a opção -n, ele imprime todas as linhas de cada arquivo, mas não as últimas N linhas, como mostrado abaixo,
G Koe

Respostas:

34

Se você tem o GNU head, você pode usar

head -n -5 file.txt

para imprimir todos, mas as últimas 5 linhas de file.txt.

E se head -n não leva argumentos negativos, tente

head -n $(( $(wc -l file.txt | awk '{print $1}') - 5 )) file.txt
user570500
fonte
10
(e rezar para que file.txt tem pelo menos seis linhas de comprimento ...)
a CVn
1
Infelizmente esta versão não-GNU não funciona com fluxos, seja
Armand
1
@ MichaelKjörling Pelo menos no Ubuntu, isso não é um problema. Se os arquivos tiverem menos linhas do que o especificado head, uma saída vazia é retornada, sem erros.
Alphaaa
Se não me engano cabeça -n 5 irá imprimir as primeiras 5 linhas, não todos, mas os últimos 5 ...
pypmannetjies
5

Aqui está uma maneira simples de apagar a última linha, que funciona no BSD, etc.

sed '$d' input.txt

A expressão lê "na última linha, apague-a". As outras linhas serão impressas, uma vez que é sed comportamento padrão.

Você poderia encadear juntos para remover várias linhas

sed '$d' input.txt | sed '$d' | sed '$d'

Que é um pouco pesado, reconhecidamente, mas faz apenas uma varredura através do arquivo.

Você também pode dar uma olhada nisso, para mais respostas: https://stackoverflow.com/questions/13380607/how-to-use-sed-to-remove-last-n-lines-of-a-file

Aqui está um one-liner adaptado de um dos meus favoritos lá:

N=10
sed -n -e ':a' -e "1,$N!{P;N;D;};N;ba"

Eu me diverti decifrando aquele, e espero que você também o faça (: Faz buffer N linhas como digitaliza, mas por outro lado é bastante eficiente.

jwd
fonte
4
head file.txt               # first 10 lines
tail file.txt               # last 10 lines
head -n 20 file.txt         # first 20 lines
tail -n 20 file.txt         # last 20 lines
head -20 file.txt           # first 20 lines
tail -20 file.txt           # last 20 lines
head -n -5 file.txt         # all lines except the 5 last
tail -n +5 file.txt         # all lines except the 4 first, starts at line 5
Kjetil S.
fonte
1
O que isso adiciona que não foi respondido na resposta aceita? Além disso, como com as outras respostas, algumas linhas de explicação da sua resposta melhorariam muito.
music2myear
1
muito bom resumo
ruanhao
2

Estou curioso porque você pensa head não é uma opção:

~$ man head
...
-n, --lines=[-]K
        print the first K lines instead of the first 10; 
        with the leading `-', print all but the last K lines of each file

Isso parece se encaixar no seu propósito, usando, por exemplo:

head -n -20 yourfile.txt
Anders R. Bystrup
fonte
5
Note que isto só se aplica ao GNU head. BSD head não tem essa opção, então essa resposta não trabalho no Solaris ou outros Unixes sem GNU coreutils. O OP especificamente marcou isso com Unix e Unix-Utils também.
slhck
2
@slhck Sem mencionar o fato de que o OP mencionou que isso é para o Solaris.
a CVn
Infelizmente, alguém removeu minha menção do Solaris. Mas eu deveria ter mencionado de qualquer maneira que a versão da cabeça não suporta isso.
Hans-Peter Störr
1
Desculpe tudo. Não percebi Solaris, nem estava ciente das várias versões da cabeça.
Anders R. Bystrup
@hstoerr O Solaris está agora nas suas tags :)
slhck
0

Outra maneira de fazer isso se tail -n não terá argumentos negativos é

tac file.txt | tail -n +6 | tac

Isso removeria as últimas 5 linhas

atw31337
fonte
Obrigado! Essa é uma idéia bacana que ninguém inventou até agora. Infelizmente isso seria bastante ineficiente para o usecase que eu tinha em mente com essa pergunta: se é um arquivo grande, ele não seria completamente lido por uma ou mais vezes, como acontece com as outras soluções, mas provavelmente também seria gravado para disco para arquivos temporários por tac se não couber na memória.
Hans-Peter Störr