Ho un file foo.txt
contenente le seguenti righe:
a
b
c
Voglio un semplice comando che si traduca nel contenuto di foo.txt
essere:
a
b
Ho un file foo.txt
contenente le seguenti righe:
a
b
c
Voglio un semplice comando che si traduca nel contenuto di foo.txt
essere:
a
b
Risposte:
Utilizzando GNU sed
:
sed -i '$ d' foo.txt
L' -i
opzione non esiste nelle GNU sed
versioni precedenti alla 3.95, quindi è necessario utilizzarla come filtro con un file temporaneo:
cp foo.txt foo.txt.tmp
sed '$ d' foo.txt.tmp > foo.txt
rm -f foo.txt.tmp
Certo, in quel caso potresti anche usare head -n -1
invece di sed
.
Mac OS:
Su Mac OS X (a partire dal 10.7.4), l'equivalente del sed -i
comando sopra è
sed -i '' -e '$ d' foo.txt
$ d
una regex. È un comando sed. d
è il comando per eliminare una riga, mentre $
significa "l'ultima riga nel file". Quando si specifica una posizione (chiamata "range" in sed lingo) prima di un comando, quel comando viene applicato solo alla posizione specificata. Quindi, questo comando dice esplicitamente "nell'intervallo dell'ultima riga in un file, eliminalo". Abbastanza lucido e dritto al punto, se me lo chiedi.
Questa è di gran lunga la soluzione più veloce e più semplice, specialmente su file di grandi dimensioni:
head -n -1 foo.txt > temp.txt ; mv temp.txt foo.txt
se vuoi cancellare la prima riga usa questo:
tail -n +2 foo.txt
che significa linee di uscita che iniziano alla linea 2.
Non utilizzare sed
per eliminare le righe dalla parte superiore o inferiore di un file: è molto lento se il file è di grandi dimensioni.
head -n -1 foo.txt
è abbastanza
brew install coreutils
(utility GNU core) e usare ghead
invece di head
.
FILE=$1; TAIL=$2; head -n -${TAIL} ${FILE} > temp ; mv temp ${FILE}
per cancellare 4 linee ad esempio da myfile come: ./TAILfixer myfile 4
ovviamente prima chmod +x TAILfixer
sed
, questo comando è anche piuttosto lento
Ho avuto problemi con tutte le risposte qui perché stavo lavorando con un file ENORME (~ 300Gb) e nessuna delle soluzioni ridimensionata. Ecco la mia soluzione:
dd if=/dev/null of=<filename> bs=1 seek=$(echo $(stat --format=%s <filename> ) - $( tail -n1 <filename> | wc -c) | bc )
In parole: scopri la lunghezza del file che vuoi finire (lunghezza del file meno la lunghezza della sua ultima riga, usando bc
) e, imposta quella posizione come la fine del file ( dd
inserendo un byte di /dev/null
in esso).
Questo è veloce perché tail
inizia a leggere dalla fine e dd
sovrascriverà il file in atto anziché copiare (e analizzare) ogni riga del file, che è ciò che fanno le altre soluzioni.
NOTA: questo rimuove la linea dal file in atto! Fai 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 qualsiasi cosa , è possibile 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 quel 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 hai intenzione di utilizzarli ripetutamente e desideri la gestione degli errori e alcune altre funzionalità, puoi utilizzare il poptail
comando qui:
https://github.com/donm/evenmoreutils
truncate
non è disponibile su OS X per impostazione predefinita. Ma è facile da installare utilizzando Brew: brew install truncate
.
Utenti Mac
se si desidera solo l'output dell'ultima riga eliminato 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
-i ''
dice a sed di modificare il file sul posto, mantenendo un backup in un file con l'estensione fornita come parametro. Poiché il parametro è una stringa vuota, non viene creato alcun file di backup. -e
dice a sed di eseguire un comando. Il comando $ d
significa: trova l'ultima riga ( $
) ed eliminala ( d
).
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 "head" e / o "tail".
Ho provato la seguente sequenza di comandi ed ero felice di poterlo risolvere semplicemente usando il comando "tail" [con le opzioni disponibili su Mac]. Quindi, se sei su Mac e vuoi usare solo "tail" per risolvere questo problema, puoi usare questo comando:
cat file.txt | tail -r | tail -n +2 | tail -r
1> tail -r: inverte semplicemente l'ordine delle linee nel suo input
2> tail -n +2: stampa tutte le righe a partire dalla seconda riga nel suo input
ghead -n -1
awk 'NR>1{print buf}{buf = $0}'
In sostanza, questo codice dice quanto segue:
Per ogni riga successiva alla prima, stampare la riga bufferizzata
per ogni riga, ripristinare il buffer
Il buffer è ritardato di una riga, quindi finisci per stampare le righe da 1 a n-1
awk "NR != `wc -l < text.file`" text.file |> text.file
Questo frammento fa il trucco.
Entrambe queste soluzioni sono qui in altre forme. Ho trovato questi un po 'più pratici, chiari e utili:
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}
Utilizzando troncare:
BADLINESCOUNT=1
ORIGINALFILE=/tmp/whatever
truncate -s $(printf "$(stat --format=%s ${ORIGINALFILE}) - $(tail -n${BADLINESCOUNT} ${ORIGINALFILE} | wc -c)\n" | bc ) ${ORIGINALFILE}
sed '$d' ~/path/to/your/file/name
sed -i '' -e '$ d' ~/path/to/your/file/name
Ecco come puoi farlo manualmente (personalmente uso molto questo metodo quando devo rimuovere rapidamente l'ultima riga di un file):
vim + [FILE]
Quello +
segno lì significa che quando il file viene aperto nell'editor di testo vim, il cursore si posizionerà sull'ultima riga del file.
Ora basta premere d
due volte sulla tastiera. Questo farà esattamente quello che vuoi: rimuovere l'ultima riga. Successivamente, premere :
seguito da, x
quindi premere Enter
. Ciò salverà le modifiche e ti riporterà alla shell. Ora, l'ultima riga è stata rimossa correttamente.
sed -i
comando sopra èsed -i '' -e '$ d' foo.txt
. Inoltre,head -n -1
attualmente non funziona su un Mac.