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 wc
wywołania:
## grep "^.{$( wc -L F )}$" F
wc
Stosuje 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 grep
uż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: grep
Opcja -E
( --extended-regexp
) pozwala nie uciec przed {}
czytelnością. Opcja -m 1
( --max-count=1
) powoduje zatrzymanie po znalezieniu pierwszego wiersza. Komenda <
in wc
zapisuje plik na standardowe wejście, aby zapobiec wc
drukowaniu 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 f
dla nazwy pliku; Każdy $f
w 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 wc
i wiersze zapisane przez grep
był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.)