Grep pierwsza najdłuższa linia
grep -Em1 "^.{$(wc -L <file.txt)}\$" file.txt
Polecenie jest niezwykle trudne do odczytania bez praktyki, ponieważ łączy w sobie składnię powłoki i wyrażenia regularnego.
Dla wyjaśnienia najpierw użyję uproszczonego pseudokodu. Linie zaczynające się od ##nie działają w powłoce.
Ten uproszczony kod używa nazwy pliku F i pomija cytowanie i fragmenty wyrażeń regularnych dla czytelności.
Jak to działa
Polecenie składa się z dwóch części, a grep- i wcwywołania:
## grep "^.{$( wc -L F )}$" F
wcStosuje się ekspansji procesu, $( ... )tak że prowadzony jest przed grep. Oblicza długość najdłuższej linii. Składnia rozszerzania powłoki jest mieszana ze składnią wzorca wyrażeń regularnych w mylący sposób, więc rozpakuję rozwinięcie procesu:
## wc -L F
42
## grep "^.{42}$" F
Tutaj rozszerzenie procesu zostało zastąpione wartością, którą zwróci, tworząc grepużywany wiersz poleceń. Możemy teraz łatwiej odczytać wyrażenie regularne: Pasuje dokładnie od początku ( ^) do końca ( $) linii. Wyrażenie między nimi pasuje do dowolnego znaku oprócz znaku nowej linii, powtarzanego 42 razy. Łącznie, czyli wiersze składające się dokładnie z 42 znaków.
Wróćmy teraz do prawdziwych poleceń powłoki: grepOpcja -E( --extended-regexp) pozwala nie uciec przed {}czytelnością. Opcja -m 1( --max-count=1) powoduje zatrzymanie po znalezieniu pierwszego wiersza. Komenda <in wczapisuje plik na standardowe wejście, aby zapobiec wcdrukowaniu nazwy pliku wraz z jego długością.
Które najdłuższe linie?
Aby przykłady były bardziej czytelne, a nazwa pliku występowała dwukrotnie, użyję zmiennej fdla nazwy pliku; Każdy $fw tym przykładzie można zastąpić nazwą pliku.
f="file.txt"
Pokaż pierwszą najdłuższą linię - pierwszą linię, która jest tak długa jak najdłuższa linia:
grep -E -m1 "^.{$(wc -L <"$f")}\$" "$f"
Pokaż wszystkie najdłuższe linie - wszystkie linie, które są tak długie jak najdłuższa linia:
grep -E "^.{$(wc -L <"$f")}\$" "$f"
Pokaż ostatnią najdłuższą linię - ostatnia linia, która jest tak długa jak najdłuższa linia:
tac "$f" | grep -E -m1 "^.{$(wc -L <"$f")}\$"
Pokaż pojedynczą najdłuższą linię - najdłuższą linię dłuższą niż wszystkie inne linie, lub zawieść:
[ $(grep -E "^.{$(wc -L <"$f")}\$" "$f" | wc -l) = 1 ] && grep -E "^.{$(wc -L <"$f")}\$" "$f"
(Ostatnie polecenie jest nawet bardziej nieefektywne niż inne, ponieważ powtarza kompletne polecenie grep. Oczywiście należy je rozłożyć, aby dane wyjściowe wci wiersze zapisane przez grepbyły zapisywane w zmiennych.
Zauważ, że wszystkie najdłuższe linie mogą w rzeczywistości być wszystkimi liniami Aby zapisać w zmiennej, należy zachować tylko dwa pierwsze wiersze.)