Каналы, как делают поток данных в конвейере?

Я думаю, что самый легкий путь состоит в том, чтобы инвертировать вход перед соответствием:

<logfile tac | sed '/pattern/q' | tac
22
01.02.2015, 10:11
2 ответа

Существует общее правило буферизации, за которым следует стандартная библиотека ввода-вывода 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'
36
27.01.2020, 19:42

Это на самом деле затронуло меня некоторую мысль, чтобы понять и даже больше ответить. Отличный вопрос (я буду расширен его дальше).

Вы пренебрегали, чтобы попробовать 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 предоставил объяснение , когда я набрал последнее редактирование. Спасибо!

8
27.01.2020, 19:42

Теги

Похожие вопросы