Auf der Suche nach einer Möglichkeit, Leerzeilen am Anfang und Ende tac
einer Datei zu entfernen (mithilfe von ), bin ich über diese gestolpert:
awk 'NF {p=1} p'
Wie/warum funktioniert das?
Ich verstehe NF
das nur true
, wenn Felder vorhanden sind (wenn die Zeile keine leere Zeile ist).
Antwort1
Dadurch werden leere Zeilen am Anfang entfernt.aber nicht vom Endeeiner Datei.[Hinweis: Diese Antwort wurde vor demBearbeiten der Fragedas erwähnte tac
]
Es funktioniert wie folgt:
NF
ist die Anzahl der in der aktuellen Zeile gefundenen Felder. Wenn sie Null ist, bedeutet das, dass die Zeile entweder leer ist oderleer, d. h. es enthält höchstens Leerzeichen (vorausgesetzt, der Feldtrenner wird auf seinem Standardwert belassen, bei dem jede Anzahl aufeinanderfolgender Leerzeichen als Trennzeichen betrachtet wird).- Die aktuelle Zeile wird gedruckt, wenn eine beliebige Bedingung außerhalb von Regelblöcken () (und die nicht mit diesen verknüpft ist)
{ ... }
als ausgewertet wirdtrue
. Das Flagp
ist zunächst nicht initialisiert und wird als ausgewertetfalse
, daher wird a priori nichts gedruckt. - Sobald eine nicht leere Zeile gefunden wird (
NF
die ungleich Null ist und als ausgewertet wirdtrue
),{p=1}
wird der Regelblock aufgerufen und das Flagp
auf gesetzt1
. Danach wird der Bereichp
außerhalb des Regelblocks als ausgewertettrue
und alle nachfolgenden Zeilen (einschließlich der aktuellen, ersten nicht leeren Zeile) werden gedruckt.
Beachtendass, da das Flag p
nie zurückgesetzt wird, alle Leerzeilen nach der ersten nicht leeren Zeile ohne Filterung gedruckt werden. Wenn Sie auch am Ende Leerzeilen entfernen möchten, ist ein zweistufiger Ansatz erforderlich:
awk 'FNR==NR{if (NF) {if (!first) first=FNR; last=FNR} next}
FNR>=first && FNR<=last' input.txt input.txt
Dadurch wird die Datei zweimal verarbeitet (daher wird sie zweimal als Operand angegeben).
- Im ersten Durchgang, bei dem
FNR
der Zeilenzähler pro Datei gleichNR
dem globalen Zeilenzähler ist, identifizieren wir die erste und die letzte nicht leere Zeile. - Im zweiten Durchgang (
FNR
ist jetzt kleiner alsNR
) drucken wir nur die Zeilen zwischen (und einschließlich) der so identifizierten ersten und letzten nicht leeren Zeile.
Beachten
Wie in derAntwort von Stéphane Chazelasfunktioniert der Zwei-Durchgang-Ansatz nur mit regulären Dateien. Wenn Ihre Eingabe anderer Natur ist, finden Sie eine Lösung in der dort vorgeschlagenen Methode.
Antwort2
Verwenden Sie diese Technik, um leere Zeilen sowohl aus dem Kopf als auch aus dem Ende der Datei zu entfernen:
awk 'NF {p=1} p' file | # remove blank lines at the file head
tac | # reverse the lines
awk 'NF {p=1} p' | # remove blanks from the "new head"
tac | # re-reverse the file
sponge file # from the `moreutils` package, to overwrite the file
Antwort3
Was Dein Code macht und warum er nur leere Zeilen am Anfang der Eingabe löscht, wurde bereits erklärt in@AdminBees Antwortzum Beispiel, aber der Vollständigkeit halber schlage ich hier eine alternative Methode vor, um sowohl führende als auch nachfolgende Leerzeilen zu entfernen, ohne die Datei zweimal durchgehen zu müssen (was nur bei normalen Dateien und nicht bei beliebigen Eingaben funktionieren würde).
awk '
NF {print saved $0; saved = ""; started = 1; next}
started {saved = saved $0 ORS}' < file
Dabei verzögern wir das Drucken von Leerzeilen bis zur nächsten nicht leeren Zeile, die wir danach sehen (vorausgesetzt, wir haben zuvor bereits mindestens eine nicht leere Zeile gesehen).
Antwort4
Falls es Ihnen nichts ausmacht, alle Leerzeichen oder Tabulatoren in den Leerzeilen zu überschreiben, die Sie behalten möchten, werden hiermit die Leerzeilen am Anfang und Ende entfernt:
awk 'NF{for(;c;--c)print "";print;x=1;next} x{++c}'
Es zählt, wie viele Leerzeilen zwischen nicht leeren Zeilen vorkommen, und druckt entsprechend viele Leerzeilen vor jeder nicht leeren Zeile.