Я думаю, что самый легкий путь состоит в том, чтобы инвертировать вход перед соответствием:
<logfile tac | sed '/pattern/q' | tac
Существует общее правило буферизации, за которым следует стандартная библиотека ввода-вывода C ( stdio
), которую использует большинство программ Unix. Если вывод идет на терминал, он сбрасывается в конце каждой строки; в противном случае он сбрасывается только тогда, когда буфер (8K в моей системе Linux / amd64; может быть другим в вашей) заполнен.
Если бы все ваши утилиты следовали общему правилу, вы бы увидели задержку вывода во всех ваших примерах ( cat | sed
, cat | tr
и cat | tr | sed
). Но есть исключение: GNU cat
никогда не буферизует свой вывод. Он либо не использует stdio
, либо изменяет политику буферизации по умолчанию stdio
.
Я могу быть уверен, что вы используете GNU cat
, а не какой-нибудь другой unix cat
, потому что другие не будут вести себя подобным образом. Традиционный unix cat
имеет параметр -u
для запроса небуферизованного вывода. GNU cat
игнорирует параметр -u
, потому что его вывод всегда небуферизован.
Таким образом, всякий раз, когда у вас есть канал с cat
слева, в системе GNU прохождение данных по каналу не будет задерживаться. cat
даже не идет строка за строкой - это делает ваш терминал. Пока вы вводите ввод для cat, ваш терминал находится в "каноническом" режиме - на основе строки, с клавишами редактирования, такими как backspace и ctrl-U, предлагая вам возможность отредактировать введенную строку перед ее отправкой с помощью Enter .
В примере cat | tr | sed
, tr
по-прежнему получает данные от cat
, как только вы нажимаете Enter , но tr
следует политике по умолчанию stdio
: его вывод идет в канал, поэтому он не сбрасывается после каждой строки. Он записывает во второй канал, когда буфер заполнен или когда получен EOF, в зависимости от того, что наступит раньше.
sed
также следует политике по умолчанию stdio
, но его вывод направляется на терминал, поэтому он будет записывать каждую строку, как только закончит с ней. Это влияет на то, сколько вы должны ввести, прежде чем что-то появится на другом конце конвейера - если sed
буферизует свой вывод блочно, вам придется вводить вдвое больше (чтобы заполнить tr
буфер вывода и буфер вывода sed
).
GNU sed
имеет параметр -u
, поэтому, если вы измените порядок и примените cat | sed -u | tr
, вы увидите, что результат сразу же появится снова. . (Параметр sed -u
может быть доступен где-нибудь еще, но я не думаю, что это древняя традиция unix, например cat -u
) Насколько я могу судить, для tr
.
Существует утилита под названием stdbuf
, которая позволяет изменять режим буферизации любой команды, использующей значения по умолчанию stdio
. Это немного хрупко, поскольку использует LD_PRELOAD
для выполнения того, для чего библиотека C не предназначена, но в данном случае, похоже, работает:
cat | stdbuf -o 0 tr '[:lower:]' '[:upper:]' | sed 'p'
Это на самом деле затронуло меня некоторую мысль, чтобы понять и даже больше ответить. Отличный вопрос (я буду расширен его дальше).
Вы пренебрегали, чтобы попробовать TR | SED
В ваших предметах отладки выше:
>tr '[:lower:]' '[:upper:]' | sed 'p'
i am writing
still writing
now ctrl-d
I AM WRITING
I AM WRITING
STILL WRITING
STILL WRITING
NOW CTRL-D
NOW CTRL-D
>
так, очевидно, TR
буферы. Узнавайте что-то новое каждый день!
Отредактируйте :
Как я думаю, что это снова, мы изолировали причину, но не предоставили объяснение. Если вы CAT | TR
, он сразу пишет, если вы CAT | SED
, он сразу пишет, но если вы TR | SED
, он ждет для EOF
. Я бы предположил, что ответ может быть похоронен в TR
или SED
исходный код, а не будет проблемой трубы.
Редактировать :
Я вижу, что Wumpus предоставил объяснение , когда я набрал последнее редактирование. Спасибо!