Grep die erste längste Zeile
grep -Em1 "^.{$(wc -L <file.txt)}\$" file.txt
Der Befehl ist ohne Übung ungewöhnlich schwer zu lesen, da er Shell- und Regexp-Syntax mischt.
Zur Erklärung verwende ich zunächst den vereinfachten Pseudocode. Die mit beginnenden Zeilen ##
verlaufen nicht in der Shell.
Dieser vereinfachte Code verwendet den Dateinamen F und lässt aus Gründen der Lesbarkeit Anführungszeichen und Teile von regulären Ausdrücken weg.
Wie es funktioniert
Der Befehl besteht aus zwei Teilen, einem grep
- und einem wc
Aufruf:
## grep "^.{$( wc -L F )}$" F
Das wc
wird in einer Prozesserweiterung verwendet $( ... )
, es wird also vorher ausgeführt grep
. Es berechnet die Länge der längsten Linie. Die Shell-Erweiterungssyntax wird auf verwirrende Weise mit der Mustersyntax für reguläre Ausdrücke gemischt, daher werde ich die Prozesserweiterung auflösen:
## wc -L F
42
## grep "^.{42}$" F
Hier wurde die Prozesserweiterung durch den Wert ersetzt, den sie zurückgeben würde, wodurch die verwendete grep
Befehlszeile erstellt wurde. Wir können den regulären Ausdruck jetzt einfacher lesen: Er stimmt genau vom Anfang ( ^
) bis zum Ende ( $
) der Zeile überein . Der Ausdruck zwischen ihnen stimmt mit jedem Zeichen außer Newline überein und wird 42 Mal wiederholt. Kombiniert sind das Zeilen, die aus genau 42 Zeichen bestehen.
Nun zurück zu echten Shell-Befehlen: Die grep
Option -E
( --extended-regexp
) erlaubt es, der {}
Lesbarkeit nicht zu entgehen . Option -m 1
( --max-count=1
) stoppt, nachdem die erste Zeile gefunden wurde. Der Befehl <
im wc
Befehl schreibt die Datei in das Standardverzeichnis, um zu verhindern, dass wc
der Dateiname zusammen mit der Länge gedruckt wird.
Welche längsten Schlangen?
Um die Beispiele bei zweimaligem Auftreten des Dateinamens lesbarer zu machen, verwende ich eine Variable f
für den Dateinamen. Jedes $f
im Beispiel könnte durch den Dateinamen ersetzt werden.
f="file.txt"
Zeige die erste längste Zeile - die erste Zeile, die so lang ist wie die längste Zeile:
grep -E -m1 "^.{$(wc -L <"$f")}\$" "$f"
Zeige alle längsten Linien - alle Linien , die so lang wie die längste Linie sind:
grep -E "^.{$(wc -L <"$f")}\$" "$f"
Zeige die letzte längste Zeile - die letzte Zeile, die so lang ist wie die längste Zeile:
tac "$f" | grep -E -m1 "^.{$(wc -L <"$f")}\$"
Zeigt die längste einzelne Zeile an - die längste Zeile ist länger als alle anderen Zeilen, oder schlägt fehl:
[ $(grep -E "^.{$(wc -L <"$f")}\$" "$f" | wc -l) = 1 ] && grep -E "^.{$(wc -L <"$f")}\$" "$f"
(Der letzte Befehl ist noch ineffizienter als die anderen, da er den vollständigen grep-Befehl wiederholt. Er sollte offensichtlich zerlegt werden, damit die Ausgabe von wc
und die von geschriebenen Zeilen grep
in Variablen gespeichert werden.
Beachten Sie, dass alle längsten Zeilen tatsächlich alle Zeilen sein können Zum Speichern in einer Variablen müssen nur die ersten beiden Zeilen beibehalten werden.)