Ich habe eine Datei foo.txt
mit den folgenden Zeilen:
a
b
c
Ich möchte einen einfachen Befehl, der zum Inhalt des foo.txt
Seins führt:
a
b
Ich habe eine Datei foo.txt
mit den folgenden Zeilen:
a
b
c
Ich möchte einen einfachen Befehl, der zum Inhalt des foo.txt
Seins führt:
a
b
Antworten:
Verwenden von GNU sed
:
sed -i '$ d' foo.txt
Die -i
Option ist in GNU sed
Versionen älter als 3.95 nicht vorhanden. Sie müssen sie daher als Filter für eine temporäre Datei verwenden:
cp foo.txt foo.txt.tmp
sed '$ d' foo.txt.tmp > foo.txt
rm -f foo.txt.tmp
In diesem Fall könnten Sie natürlich auch head -n -1
anstelle von verwenden sed
.
Mac OS:
Unter Mac OS X (ab 10.7.4) entspricht dies dem sed -i
obigen Befehl
sed -i '' -e '$ d' foo.txt
$ d
eine Regex. Es ist ein sed Befehl. d
ist der Befehl zum Löschen einer Zeile, während $
"die letzte Zeile in der Datei" bedeutet. Wenn Sie vor einem Befehl einen Ort angeben (in sed lingo als "Bereich" bezeichnet), wird dieser Befehl nur auf den angegebenen Ort angewendet. Dieser Befehl lautet also explizit "Löschen Sie im Bereich der letzten Zeile einer Datei diese". Ganz glatt und direkt auf den Punkt, wenn Sie mich fragen.
Dies ist bei weitem die schnellste und einfachste Lösung, insbesondere bei großen Dateien:
head -n -1 foo.txt > temp.txt ; mv temp.txt foo.txt
Wenn Sie die oberste Zeile löschen möchten, verwenden Sie Folgendes:
tail -n +2 foo.txt
Dies bedeutet, dass die Ausgangsleitungen ab Zeile 2 beginnen.
Nicht sed
zum Löschen von Zeilen am oberen oder unteren Rand einer Datei verwenden - es ist sehr, sehr langsam, wenn die Datei groß ist.
head -n -1 foo.txt
ist genug
brew install coreutils
(GNU Core Utilities) und ghead
stattdessen verwenden head
.
FILE=$1; TAIL=$2; head -n -${TAIL} ${FILE} > temp ; mv temp ${FILE}
Führt sie zum Löschen 4 Zeilen zum Beispiel von Meinedat als: ./TAILfixer myfile 4
natürlich zunächst durch ausführbar machenchmod +x TAILfixer
sed
ist dieser Befehl auch verdammt langsam
Ich hatte Probleme mit allen Antworten hier, weil ich mit einer RIESIGEN Datei (~ 300 GB) arbeitete und keine der Lösungen skaliert war. Hier ist meine Lösung:
dd if=/dev/null of=<filename> bs=1 seek=$(echo $(stat --format=%s <filename> ) - $( tail -n1 <filename> | wc -c) | bc )
Mit Worten: Ermitteln Sie die Länge der Datei, mit der Sie enden möchten (Länge der Datei minus Länge der Länge der letzten Zeile, mit bc
), und legen Sie diese Position als Ende der Datei fest (indem dd
Sie ein Byte auf /dev/null
eingeben es).
Dies ist schnell, da das tail
Lesen am Ende beginnt und dd
die Datei an Ort und Stelle überschreibt, anstatt jede Zeile der Datei zu kopieren (und zu analysieren), wie dies bei den anderen Lösungen der Fall ist.
HINWEIS: Dadurch wird die Zeile aus der vorhandenen Datei entfernt! Erstellen Sie ein Backup oder testen Sie eine Dummy-Datei, bevor Sie sie in Ihrer eigenen Datei ausprobieren!
Sie können verwenden, um die letzte Zeile aus einer Datei zu entfernen, ohne die gesamte Datei zu lesen oder etwas neu zu schreiben
tail -n 1 "$file" | wc -c | xargs -I {} truncate "$file" -s -{}
Um die letzte Zeile zu entfernen und sie auch auf stdout zu drucken ("pop" it), können Sie diesen Befehl kombinieren mit tee
:
tail -n 1 "$file" | tee >(wc -c | xargs -I {} truncate "$file" -s -{})
Diese Befehle können eine sehr große Datei effizient verarbeiten. Dies ähnelt der Antwort von Yossi und ist von dieser inspiriert, vermeidet jedoch die Verwendung einiger zusätzlicher Funktionen.
Wenn Sie diese wiederholt verwenden und Fehlerbehandlung und einige andere Funktionen wünschen, können Sie den poptail
Befehl hier verwenden:
https://github.com/donm/evenmoreutils
truncate
Ist unter OS X standardmäßig nicht verfügbar. Die Installation mit Brew ist jedoch einfach : brew install truncate
.
Mac-Benutzer
Wenn Sie nur die letzte Zeile löschen möchten, ohne die Datei selbst zu ändern, tun Sie dies
sed -e '$ d' foo.txt
Wenn Sie die letzte Zeile der Eingabedatei selbst löschen möchten, tun Sie dies
sed -i '' -e '$ d' foo.txt
-i ''
weist sed an, die Datei an Ort und Stelle zu ändern, während ein Backup in einer Datei mit der als Parameter angegebenen Erweiterung gespeichert wird. Da der Parameter eine leere Zeichenfolge ist, wird keine Sicherungsdatei erstellt. -e
weist sed an, einen Befehl auszuführen. Der Befehl $ d
bedeutet: Finde die letzte Zeile ( $
) und lösche sie ( d
).
Auf dem Mac funktioniert head -n -1 nicht. Und ich habe versucht, eine einfache Lösung zu finden [ohne mir Gedanken über die Verarbeitungszeit zu machen], um dieses Problem nur mit den Befehlen "head" und / oder "tail" zu lösen.
Ich habe die folgende Befehlsfolge ausprobiert und war froh, dass ich sie nur mit dem Befehl "tail" [mit den auf dem Mac verfügbaren Optionen] lösen konnte. Wenn Sie also auf einem Mac arbeiten und nur "tail" verwenden möchten, um dieses Problem zu lösen, können Sie den folgenden Befehl verwenden:
cat file.txt | Schwanz -r | Schwanz -n +2 | Schwanz -r
1> tail -r: kehrt einfach die Reihenfolge der Zeilen in seiner Eingabe um
2> tail -n +2: Hiermit werden alle Zeilen ab der zweiten Zeile in der Eingabe gedruckt
ghead -n -1
awk 'NR>1{print buf}{buf = $0}'
Im Wesentlichen sagt dieser Code Folgendes:
Drucken Sie für jede Zeile nach der ersten die gepufferte Zeile
Setzen Sie für jede Zeile den Puffer zurück
Der Puffer ist um eine Zeile verzögert, sodass Sie am Ende die Zeilen 1 bis n-1 drucken
awk "NR != `wc -l < text.file`" text.file |> text.file
Dieses Snippet macht den Trick.
Beide Lösungen gibt es hier in anderen Formen. Ich fand diese etwas praktischer, klarer und nützlicher:
Verwenden von 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}
Verwenden von Truncate:
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
So können Sie es manuell machen (ich persönlich verwende diese Methode häufig, wenn ich die letzte Zeile in einer Datei schnell entfernen muss):
vim + [FILE]
Dieses +
Zeichen bedeutet, dass beim Öffnen der Datei im vim-Texteditor der Cursor in der letzten Zeile der Datei positioniert wird.
Drücken d
Sie jetzt einfach zweimal auf Ihrer Tastatur. Dies macht genau das, was Sie wollen - entfernen Sie die letzte Zeile. Drücken Sie danach :
gefolgt von x
und dann Enter
. Dadurch werden die Änderungen gespeichert und Sie kehren zur Shell zurück. Jetzt wurde die letzte Zeile erfolgreich entfernt.
sed -i
obigen Befehlsed -i '' -e '$ d' foo.txt
. Funktionierthead -n -1
derzeit auch nicht auf einem Mac.