Ich habe viele Textdateien in einem Verzeichnis und möchte die letzte Zeile jeder Datei im Verzeichnis entfernen.
Wie kann ich es tun?
Ich habe viele Textdateien in einem Verzeichnis und möchte die letzte Zeile jeder Datei im Verzeichnis entfernen.
Wie kann ich es tun?
Antworten:
Sie können diesen netten Oneliner verwenden, wenn Sie GNU haben sed
.
sed -i '$ d' ./*
Dadurch wird die letzte Zeile jeder nicht ausgeblendeten Datei im aktuellen Verzeichnis entfernt. Switch -i
for GNU sed
bedeutet, an Ort und Stelle zu arbeiten, und '$ d'
befiehlt sed
, die letzte Zeile zu löschen ( $
bedeutet "Letzte" und " d
Löschen").
-i
einen GNUism, also ist das strittig, aber ich würde meinen alten Bart verlieren, wenn ich nicht darauf hinweisen würde, dass einige ältere Versionen von sed
es dir nicht erlauben, Leerzeichen zwischen den $
und d
(oder) zu setzen. im Allgemeinen zwischen dem Muster und dem Befehl).
*(.)
Glob für reguläre Dateien verwenden, ich kenne keine anderen Shells.
Die anderen Antworten haben alle Probleme, wenn das Verzeichnis etwas anderes als eine reguläre Datei oder eine Datei mit Leerzeichen / Zeilenumbrüchen im Dateinamen enthält. Folgendes funktioniert unabhängig davon:
find "$dir" -type f -exec sed -i '$d' '{}' '+'
find "$dir" -type f
: Finden Sie die Dateien im Verzeichnis $dir
-type f
welche sind reguläre Dateien;-exec
Führen Sie den Befehl für jede gefundene Datei aussed -i
: Bearbeiten Sie die Dateien an Ort und Stelle;'$d'
: lösche ( d
) die letzte ( $
) Zeile.'+'
: weist find an, weiterhin Argumente hinzuzufügen sed
(etwas effizienter, als den Befehl für jede Datei einzeln auszuführen, dank @zwol).Wenn Sie in die Unterverzeichnisse absteigen wollen nicht, dann können Sie das Argument hinzufügen -maxdepth 1
zu find
.
find
dies effizienter geschrieben find $dir -type f -exec sed -i '$d' '{}' '+'
.)
-print0
ist nicht im vollen Befehl vorhanden, warum es in der Erklärung setzen?
-depth 0
nicht (findutils 4.4.2), sollte es stattdessen sein -maxdepth 1
.
-exec
.
Wenn Sie GNU verwenden sed -i '$d'
, müssen Sie die gesamte Datei lesen und eine Kopie davon ohne die letzte Zeile erstellen, während es viel effizienter wäre, die Datei nur an Ort und Stelle zu kürzen (zumindest bei großen Dateien).
Mit GNU truncate
können Sie:
for file in ./*; do
[ -f "$file" ] &&
length=$(tail -n 1 "$file" | wc -c) &&
[ "$length" -gt 0 ] &&
truncate -s "-$length" "$file"
done
Wenn die Dateien relativ klein sind, ist dies wahrscheinlich weniger effizient, da mehrere Befehle pro Datei ausgeführt werden.
Beachten Sie, dass für Dateien, die zusätzliche Bytes nach dem letzten Zeilenumbruchzeichen (nach der letzten Zeile) oder, mit anderen Worten, eine nicht begrenzte letzte Zeile enthalten , je nach tail
Implementierung tail -n 1
nur diese zusätzlichen Bytes (wie GNU tail
) zurückgegeben werden. oder die letzte (richtig begrenzte) Zeile und diese zusätzlichen Bytes.
|wc -c
im tail
anruf? (oder a ${#length}
)
${#length}
würde nicht funktionieren, da Zeichen, nicht Bytes, gezählt werden, und $(...)
würde das abschließende Zeilenumbruchzeichen entfernen, so ${#...}
dass es um eins versetzt wäre, selbst wenn alle Zeichen Einzelbytes wären.
Ein portablerer Ansatz:
for f in ./*
do
test -f "$f" && ed -s "$f" <<\IN
d
w
q
IN
done
Ich glaube nicht, dass dies einer Erklärung bedarf ... außer vielleicht, dass dies in diesem Fall d
dasselbe ist, $d
da ed
standardmäßig die letzte Zeile ausgewählt wird.
Dies sucht nicht rekursiv und verarbeitet keine versteckten Dateien (auch Dotfiles genannt).
Wenn Sie auch diese bearbeiten möchten, lesen Sie Wie Sie versteckte Dateien in einem Verzeichnis mit * abgleichen
[[]]
, []
ist es vollständig POSIX-kompatibel. ( [[ ... ]]
Ist ein Bashismus.)
[[
kein Bashismus ist )
POSIX-kompatibler Einzeiler für alle Dateien, die rekursiv im aktuellen Verzeichnis beginnen, einschließlich Punktdateien:
find . -type f -exec sh -c 'for f; do printf "\$d\nx\n" | ex "$f"; done' sh {} +
.txt
Nur für Dateien, nicht rekursiv:
find . -path '*/*/*' -prune -o -type f -name '*.txt' -exec sh -c 'for f; do printf "\$d\nx\n" | ex "$f"; done' sh {} +
Siehe auch: