Powód dlaczego
tac file | grep foo | head -n 1
nie kończy się przy pierwszym meczu z powodu buforowania.
Zwykle head -n 1
kończy się po przeczytaniu linii. Więc grep
powinien dostać SIGPIPE i wyjść tak szybko, jak tylko napisze drugą linię.
Ale dzieje się tak, ponieważ ponieważ jego wyjście nie trafia do terminala, grep
buforuje je. Oznacza to, że nie pisze tego, dopóki nie zgromadzi wystarczającej ilości (4096 bajtów w moim teście z GNU grep).
Oznacza to, że grep
nie wyjdzie przed zapisaniem 8192 bajtów danych, więc prawdopodobnie sporo wierszy.
Dzięki GNU grep
możesz sprawić, że wyjdzie wcześniej, używając polecenia, --line-buffered
które wypisuje wiersze, gdy tylko zostaną znalezione, niezależnie od tego, czy przejdzie do terminala, czy nie. Opuszczałby grep
wtedy drugą znalezioną linię.
Ale z GNU i grep
tak możesz użyć -m 1
zamiast tego, jak pokazał @terdon, co jest lepsze, gdy wychodzi z pierwszego meczu.
Jeśli grep
nie grep
jesteś GNU , możesz użyć sed
lub awk
zamiast tego. Ale tac
będąc poleceniem GNU, wątpię, abyś znalazł system, w tac
którym grep
nie ma GNU grep
.
tac file | sed "/$pattern/!d;q" # BRE
tac file | P=$pattern awk '$0 ~ ENVIRON["P"] {print; exit}' # ERE
Niektóre systemy muszą tail -r
robić to samo co GNU tac
.
Zauważ, że w przypadku zwykłych (możliwych do przeglądania) plików tac
i tail -r
są one wydajne, ponieważ odczytują pliki do tyłu, nie tylko czytają plik w całości przed wydrukowaniem go do tyłu (tak jak w przypadku sed @ slm lub tac
w przypadku plików nieregularnych) .
W systemach, w których ani tac
nie tail -r
są dostępne, jedynymi opcjami są ręczne odczytywanie wstecz przy użyciu języków programowania takich jak perl
lub użycie:
grep -e "$pattern" file | tail -n1
Lub:
sed "/$pattern/h;$!d;g" file
Ale oznacza to znalezienie wszystkich dopasowań i wydrukowanie tylko ostatniego.