Powód dlaczego
tac file | grep foo | head -n 1
nie kończy się przy pierwszym meczu z powodu buforowania.
Zwykle head -n 1kończy się po przeczytaniu linii. Więc greppowinien dostać SIGPIPE i wyjść tak szybko, jak tylko napisze drugą linię.
Ale dzieje się tak, ponieważ ponieważ jego wyjście nie trafia do terminala, grepbuforuje 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 grepnie wyjdzie przed zapisaniem 8192 bajtów danych, więc prawdopodobnie sporo wierszy.
Dzięki GNU grepmożesz sprawić, że wyjdzie wcześniej, używając polecenia, --line-bufferedktóre wypisuje wiersze, gdy tylko zostaną znalezione, niezależnie od tego, czy przejdzie do terminala, czy nie. Opuszczałby grepwtedy drugą znalezioną linię.
Ale z GNU i greptak możesz użyć -m 1zamiast tego, jak pokazał @terdon, co jest lepsze, gdy wychodzi z pierwszego meczu.
Jeśli grepnie grepjesteś GNU , możesz użyć sedlub awkzamiast tego. Ale tac będąc poleceniem GNU, wątpię, abyś znalazł system, w tacktórym grepnie 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 -rrobić to samo co GNU tac.
Zauważ, że w przypadku zwykłych (możliwych do przeglądania) plików taci tail -rsą 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 tacw przypadku plików nieregularnych) .
W systemach, w których ani tacnie tail -rsą dostępne, jedynymi opcjami są ręczne odczytywanie wstecz przy użyciu języków programowania takich jak perllub 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.