Szukam najprostszej metody wydrukowania najdłuższej linii w pliku. Zrobiłem trochę googlingu i, co zaskakujące, nie mogłem znaleźć odpowiedzi. Często drukuję długość najdłuższej linii w pliku, ale nie wiem jak wydrukować najdłuższą linię. Czy ktoś może dostarczyć rozwiązanie do wydrukowania najdłuższej linii w pliku? Z góry dziękuję.
35
Odpowiedzi:
UPD : podsumowanie wszystkich porad w komentarzach
źródło
cat
), jak i użycie potoku są kosztownymi operacjami, nie wspominając już o tym, że awk może po prostu czytać plik. Wpływ na wydajność jest zdecydowanie zauważalny, jeśli odbywa się to często, a mimo to całkowicie nadużywaszcat
.cat
nie jest tu bezużyteczny. Może być bezużyteczny dla komputera, ale dla ludzkiego czytelnika może stanowić wartość. Pierwszy wariant wyraźnie pokazuje dane wejściowe. Przepływ jest bardziej naturalny (od lewej do prawej). W drugim przypadku nie wiesz, co to jest wejście, chyba że przewiniesz okno.cat
.< file command
działa dobrze.< filename command
jest równoważne zfilename < command
każdą próbowaną powłoką. Ale kiedy zdasz sobie z tego sprawę, możesz z niego skorzystać, pisząc długie potoki, które wyraźnie pokazują kierunek przepływu danych (bez konieczności wywoływania dodatkowego polecenia):< input-file command1 | command2 | command3 > output-file
źródło
Najpierw odczytuje plik wewnątrz podstawienia polecenia i wyświetla długość najdłuższej linii (poprzednio
expand
konwertuje tabulacje na spacje, aby przezwyciężyć semantykęwc -L
- każda tabulacja w linii doda 8 zamiast 1 do długości linii). Ta długość jest następnie używana wsed
wyrażeniu oznaczającym „znajdź wiersz o tej liczbie znaków, wydrukuj go, a następnie zakończ”. Więc to może być tak optymalne, jak najdłuższa linia jest blisko początku pliku, heheh (dziękuję za niesamowite i konstruktywne komentarze).Innym, pomyślałem wcześniej niż sed (w bash):
źródło
-L, --max-line-length
drukuje długość najdłuższej linii, zgodnie ze stroną podręcznika, ale jeśli kopiesz głębiej (na przykład w przypadku błędnych / nieoczekiwanych wyników), zauważysz, że ta opcja zwiększa długość o 8 dla każdego 1 znaku tab\x09
zobacz ten Q / A dla systemów Unix i Linuxsed -rn "/.{$(<file expand -t1 |wc -L)}/p" file
read line
zinterpretuje odwróconego ukośnika znaki jak dosłownym char, np\A
resloves toA
, co oczywiście skutecznie zgłasza krótszy niż rzeczywisty bajt wykorzystanie ... Aby zapobiec temu uciekł interpretację, przeznaczenie:read -r line
. . . . Ponadto, aby wersja sed + wc zakończyła się po pierwszej „najdłuższej linii”, zmieńp
na{p;q}
…sed -rn "/.{$(<file expand -t1 |wc -L)}/{p;q}" file
Oto rozwiązanie Perla:
Lub, jeśli chcesz wydrukować wszystkie najdłuższe linie
Ponieważ nie miałem nic lepszego do roboty, przeprowadziłem testy porównawcze dla pliku tekstowego 625M. O dziwo, moje rozwiązanie Perla było konsekwentnie szybsze niż inne. To prawda, że różnica w stosunku do przyjętego
awk
rozwiązania jest niewielka, ale istnieje. Oczywiście rozwiązania drukujące wiele linii są wolniejsze, więc posortowałem według typu, od najszybszego do najwolniejszego.Wydrukuj tylko jedną z najdłuższych linii:
Wydrukuj wszystkie najdłuższe linie:
źródło
Grep pierwsza najdłuższa linia
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
- iwc
wywołania:## grep "^.{$( wc -L F )}$" F
wc
Stosuje się ekspansji procesu,$( ... )
tak że prowadzony jest przedgrep
. 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<
inwc
zapisuje plik na standardowe wejście, aby zapobiecwc
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.Pokaż pierwszą najdłuższą linię - pierwszą linię, która jest tak długa jak najdłuższa linia:
Pokaż wszystkie najdłuższe linie - wszystkie linie, które są tak długie jak najdłuższa linia:
Pokaż ostatnią najdłuższą linię - ostatnia linia, która jest tak długa jak najdłuższa linia:
Pokaż pojedynczą najdłuższą linię - najdłuższą linię dłuższą niż wszystkie inne linie, lub zawieść:
(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 przezgrep
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.)
źródło
Poniższy przykład miał być i powinien być komentarzem do odpowiedzi dmitry.malikov , ale z powodu bezużytecznego wykorzystania widocznego miejsca na komentarze postanowiłem przedstawić go tutaj, gdzie przynajmniej będzie widoczny. ..
Jest to prosta odmiana metody awk dla pojedynczego przejścia dmitry'ego.
Drukuje wszystkie „równe najdłuższe” linie. (Uwaga.
delete array
To rozszerzenie gawk).źródło
W czystej bash:
źródło
_max_line[0]=${_line}
nie usuwa pozostałych wcześniejszych krótszych „najdłuższych linii” ...unset _max_line
wyczyści całą tablicę ...Opracowałem do tego mały skrypt powłoki. Wyświetla długość, numer wiersza i samą linię według długości przekraczającej określony rozmiar, np. 80 znaków:
https://github.com/lordofrain/tools/blob/master/longest-line/longest-line.sh
źródło
$*
rzadko jest to dobry pomysł, chcesz"$@"
. W/.*/
twoimawk
nic nie robi, ponieważ pasuje to również do pustych linii. Możesz uniknąć ucieczki,\$0
jeśli pojedynczo zacytujesz'EOF'
. Po co używać pustegoBEGIN{}
bloku? Wreszcie, nie potrzebujeszcat
, po prostuawk . . . "$file" | . . .
awk -vmax=15 '{len=length($0); if(len>=max){printf("%s, %d at line # %d %s\n", FILENAME, len, NR, $0);}}' file*
Możesz użyć
wc
:źródło
wc -L
wady.