Причина чому
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
Але це означає знайти всі сірники і надрукувати лише останні.