Ho un file, foo.txt
, contenente le seguenti linee:
a b c
Voglio un semplice comando che si foo.txt
nel contenuto di foo.txt
essere:
a b
Usando GNU sed
:
sed -i '$ d' foo.txt
L’opzione -i
non esiste nelle versioni di GNU sed
precedenti a 3.95, quindi devi usarlo come filtro con un file temporaneo:
cp foo.txt foo.txt.tmp sed '$ d' foo.txt.tmp > foo.txt rm -f foo.txt.tmp
Naturalmente, in quel caso potresti usare anche head -n -1
invece di sed
.
Questa è di gran lunga la soluzione più rapida e semplice, specialmente su file di grandi dimensioni:
head -n -1 foo.txt > temp.txt ; mv temp.txt foo.txt
se vuoi cancellare la riga superiore usa questo:
tail -n +2 foo.txt
che significa linee di uscita a partire dalla linea 2.
Non usare sed
per cancellare le righe dall’alto o dal basso di un file – è molto molto lento se il file è grande.
Ho avuto problemi con tutte le risposte qui perché stavo lavorando con un file ENORME (~ 300 Gb) e nessuna delle soluzioni è stata ridimensionata. Ecco la mia soluzione:
dd if=/dev/null of= bs=1 seek=$(echo $(stat --format=%s ) - $( tail -n1 | wc -c) | bc )
In parole: trova la lunghezza del file con cui vuoi finire (lunghezza del file meno la lunghezza della sua ultima riga, usando bc
) e, imposta quella posizione come la fine del file ( dd
un byte di dd
di /dev/null
su di esso).
Questo è veloce perché tail
inizia a leggere dalla fine, e dd
sovrascriverà il file invece di copiare (e analizzare) ogni riga del file, che è ciò che fanno le altre soluzioni.
NOTA: questo rimuove la linea dal file in posizione! Crea un backup o prova su un file fittizio prima di provarlo sul tuo file!
Per rimuovere l’ultima riga da un file senza leggere l’intero file o riscrivere nulla , puoi utilizzare
tail -n 1 "$file" | wc -c | xargs -I {} truncate "$file" -s -{}
Per rimuovere l’ultima riga e stamparla anche su stdout (“pop”), puoi combinare tale comando con tee
:
tail -n 1 "$file" | tee >(wc -c | xargs -I {} truncate "$file" -s -{})
Questi comandi possono elaborare in modo efficiente un file molto grande. Questo è simile e ispirato alla risposta di Yossi, ma evita di usare alcune funzioni extra.
Se li usi ripetutamente e vuoi la gestione degli errori e alcune altre funzionalità, puoi usare il comando poptail
qui: https://github.com/donm/evenmoreutils
Utenti Mac
se si desidera solo l’output dell’ultima riga cancellata senza modificare il file stesso
sed -e '$ d' foo.txt
se si desidera eliminare l’ultima riga del file di input stesso
sed -i '' -e '$ d' foo.txt
Su Mac, head -n -1 non funzionerà. E, stavo cercando di trovare una soluzione semplice [senza preoccuparmi del tempo di elaborazione] per risolvere questo problema usando solo i comandi “testa” e / o “coda”.
Ho provato la seguente sequenza di comandi ed ero felice di poterlo risolvere usando il comando “tail” [con le opzioni disponibili su Mac]. Quindi, se sei su Mac e vuoi usare solo “coda” per risolvere questo problema, puoi usare questo comando:
cat file.txt | coda -r | coda -n +2 | coda -r
1> tail -r: inverte semplicemente l’ordine delle righe nel suo input
2> tail -n +2: stampa tutte le righe a partire dalla seconda riga nel suo input
echo -e '$d\nw\nq'| ed foo.txt
awk 'NR>1{print buf}{buf = $0}'
In sostanza, questo codice dice quanto segue:
Per ogni riga dopo la prima, stampa la linea bufferizzata
per ogni riga, resettare il buffer
Il buffer è ritardato di una riga, quindi si finisce per stampare le righe da 1 a n-1
awk "NR != `wc -l < text.file`" text.file |> text.file
Questo snippet fa il trucco.
Entrambe queste soluzioni sono qui in altre forms. Ho trovato questi un po ‘più pratico, chiaro e utile:
Usando dd:
BADLINESCOUNT=1 ORIGINALFILE=/tmp/whatever dd if=${ORIGINALFILE} of=${ORIGINALFILE}.tmp status=none bs=1 count=$(printf "$(stat --format=%s ${ORIGINALFILE}) - $(tail -n${BADLINESCOUNT} ${ORIGINALFILE} | wc -c)\n" | bc ) /bin/mv -f ${ORIGINALFILE}.tmp ${ORIGINALFILE}
Usando truncate:
BADLINESCOUNT=1 ORIGINALFILE=/tmp/whatever truncate -s $(printf "$(stat --format=%s ${ORIGINALFILE}) - $(tail -n${BADLINESCOUNT} ${ORIGINALFILE} | wc -c)\n" | bc ) ${ORIGINALFILE}
Rubino (1.9+)
ruby -ne 'BEGIN{prv=""};print prv ; prv=$_;' file