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