Причина чому
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робити те саме, що tacробить GNU .
Зауважте, що для звичайних (доступних для пошуку) файлів tacі tail -rефективні, оскільки вони читають файли назад, вони не просто читають файл повністю в пам'яті перед тим, як надрукувати його назад (як би підходив @ slm або tacна нерегулярні файли) .
У системах, де немає tacні tail -rдоступних, єдиними варіантами є реалізація зворотного читання вручну з такими мовами програмування, як perlі використання:
grep -e "$pattern" file | tail -n1
Або:
sed "/$pattern/h;$!d;g" file
Але це означає знайти всі сірники і надрукувати лише останні.