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