Di fronte alla coda: tutte le linee tranne le ultime n linee


36

Come posso eliminare le ultime n righe di un file con un filtro della riga di comando unix?

Sarebbe un po 'l'opposto di tail: tailscarta le prime n righe ma passa il resto attraverso, ma voglio che il comando installi tutto tranne le ultime n righe.

Sfortunatamente non ho trovato nulla del genere - non headaiuta anche. EDIT : almeno in Solaris non accetta argomenti negativi.

Aggiornamento: sono principalmente interessato a una soluzione che funziona per file di grandi dimensioni, ad esempio file di registro, in cui potresti voler controllare cosa è successo negli ultimi minuti.


Cordiali saluti quando si usa head: Posizionando '-' davanti al numero con l'opzione -n, stampa tutte le righe di ciascun file ma non le ultime N come mostrato di seguito,
G Koe

Risposte:


38

Se hai GNU head, puoi usare

head -n -5 file.txt

per stampare tutto tranne le ultime 5 righe di file.txt.

Se head -nnon accetta argomenti negativi, provare

head -n $(( $(wc -l file.txt | awk '{print $1}') - 5 )) file.txt

11
(e prega che file.txtsia lungo almeno sei righe ...)
un CVn del

1
Purtroppo, questa versione non GNU non funziona con i flussi
Armand,

1
@ MichaelKjörling Almeno su Ubuntu, non è un problema. Se i file hanno meno righe di quelle specificate head, viene restituito un output vuoto, senza errori.
Alphaaa,

Se non sbaglio, head -n 5 stamperà le prime 5 righe, non tutte tranne le ultime 5 ...
pypmannetjies

8
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

1
Cosa aggiunge questo a cui non è stata data risposta nella risposta accettata? Inoltre, come con le altre risposte, alcune righe di spiegazione della risposta migliorerebbero notevolmente.
music2myear,

1
ottimo riassunto
ruanhao

5

Ecco un modo semplice per eliminare l'ultima riga, che funziona su BSD, ecc.

sed '$d' input.txt

L'espressione legge "sull'ultima riga, eliminala". Le altre righe verranno stampate, poiché si tratta seddel comportamento predefinito.

È possibile unirli insieme per rimuovere più righe

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

Il che è un po 'pesante, è vero, ma esegue solo una scansione del file.

Puoi anche dare un'occhiata a questo, per ulteriori risposte: https://stackoverflow.com/questions/13380607/how-to-use-sed-to-remove-last-n-lines-of-a-file

Ecco un one-liner adattato da uno dei miei preferiti lì:

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

Mi sono divertito a decifrare quello, e spero che lo facciate anche voi: fa le Nlinee di buffer mentre scansiona, ma per il resto è abbastanza efficiente.


3

Sono curioso di sapere perché pensi che headnon sia un'opzione:

~$ 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

Questo sembra adattarsi al tuo scopo, usando, ad esempio:

head -n -20 yourfile.txt

5
Nota che questo vale solo per GNU head. BSD headnon ha questa opzione, quindi questa risposta non funzionerà su Solaris o altri Unix senza coreutils GNU. L'OP ha taggato questo in modo specifico anche con Unix e Unix-Utils.
slhck,

2
@slhck Per non parlare del fatto che l'OP ha menzionato che questo è per Solaris.
un CVn

Purtroppo qualcuno ha rimosso la mia menzione di Solaris. Ma avrei dovuto menzionare comunque che la versione di Head non lo supporta.
Hans-Peter Störr,

1
Mi dispiace tutto. Non ho notato Solaris, né ero a conoscenza delle varie versioni di Head.
Anders R. Bystrup,

1
@hstoerr Solaris è ora nei tag :)
slhck

0

Un altro modo per farlo se tail -nnon accetta argomenti negativi è

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

Ciò eliminerebbe le ultime 5 righe


Grazie! Questa è un'idea ingegnosa che nessuno ha trovato finora. Sfortunatamente sarebbe del tutto inefficiente per il caso che avevo in mente con questa domanda: se si tratta di un file di grandi dimensioni, non solo verrebbe letto completamente una o più volte, come con le altre soluzioni, ma probabilmente verrebbe anche scritto su disco su file temporanei di tac se non si adatta alla memoria.
Hans-Peter Störr,

@ Hans-Peter Molto vero. Ho deciso di scrivere uno script python3 per questo. Prova questo github.com/atw31337/donkey . Consiglio di utilizzare le opzioni di output. Funzionano molto più velocemente rispetto all'uso dei reindirizzamenti.
atw31337,

Ben scritto! Tuttavia, legge il file due volte, il che non è realmente necessario se si esegue il buffer delle ultime n righe, e questo è un problema su file di grandi dimensioni. Personalmente non ne ho più bisogno, ma nel caso in cui ti diverta a migliorarlo e altre persone ne hanno bisogno ... Dopotutto, c'erano alcuni Mi piace e segnalibri sulla domanda.
Hans-Peter Störr,

@ Hans-Peter. La dimensione del buffer dipende dal numero di righe da rimuovere. Questo potrebbe essere un problema se fosse necessario eliminare un numero molto elevato di righe dal file. Per evitare problemi relativi alla memoria, ho riscritto lo script per utilizzare il metodo di conteggio delle righe con valori n elevati e un metodo di buffering con valori n inferiori; tuttavia, dopo averlo testato su un file molto grande, il metodo di conteggio delle righe originale è ancora più veloce. Sembra che l'overhead di gestione del buffer superi l'overhead del conteggio delle righe ... o mi manchi qualcosa.
atw31337,

Bello, ma per Mac OS X variante BSD non esiste un comando tac per impostazione predefinita. :( Questo tipo di sconfigge il caso d'uso.
ingyhere il
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.