Причина по которой
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
Но это значит найти все совпадения и напечатать только последний.