Причина по которой
tac file | grep foo | head -n 1
не останавливается на первом матче из-за буферизации.
Обычно head -n 1
выходит после прочтения строки. Поэтому grep
следует получить SIGPIPE и завершить работу, как только он напишет вторую строку.
Но что происходит, так это потому, что его вывод не идет в терминал, grep
буферизует его. То есть он не пишет его, пока не накопит достаточно (4096 байт в моем тесте с GNU grep).
Это означает, что grep
он не завершится до того, как записал 8192 байта данных, так что, вероятно, довольно много строк.
С GNU grep
вы можете сделать так, чтобы он выходил быстрее, используя команду, --line-buffered
которая говорит ему писать строки, как только они найдены, независимо от того, идет ли к терминалу или нет. Так grep
что тогда выходил бы на второй строке, которую он находит.
Но с GNU в grep
любом случае вы можете использовать -m 1
вместо этого, как показало @terdon, что лучше, когда он выходит при первом совпадении.
Если ваш grep
не GNU grep
, то вы можете использовать sed
или awk
вместо. Но, tac
будучи командой GNU, я сомневаюсь, что вы найдете систему, в tac
которой grep
нет GNU grep
.
tac file | sed "/$pattern/!d;q" # BRE
tac file | P=$pattern awk '$0 ~ ENVIRON["P"] {print; exit}' # ERE
Некоторые системы должны tail -r
делать то же самое, что и GNU tac
.
Обратите внимание , что для регулярных (доступных для поиска) файлов, tac
и tail -r
являются эффективными , потому что они делают читать файлы назад, они не просто чтение файла полностью в памяти перед печатью назад (как @ ОДС это СЭД подхода или tac
на нерегулярных файлах будет) ,
В системах, где ни нет, tac
ни tail -r
доступно, единственные варианты - реализовать обратное чтение вручную с помощью языков программирования, таких как perl
или использующих:
grep -e "$pattern" file | tail -n1
Или:
sed "/$pattern/h;$!d;g" file
Но это значит найти все совпадения и напечатать только последний.