- Вопрос или проблема
- gawk
- mawk
- Ответ или решение
- Почему стандартный вывод mawk имеет буферизацию, даже когда он направляется в терминал?
- 1. Понимание буферизации в Unix
- 2. Почему mawk буферизует ввод?
- 3. Пример: Обработка данных с использованием pipeline
- 4. Сравнение с другими утилитами
- 5. Как изменить поведение mawk?
- Заключение
Вопрос или проблема
Я осведомлён о том, что STDOUT
обычно буферизуется такими командами, как mawk
(но не gawk
), grep
, sed
и так далее, если не использовать соответствующие опции (т.е. mawk --Winteractive
, или grep --line-buffered
, или sed --unbuffered
). Но буферизация не происходит, когда STDOUT
является терминалом/TTY, в этом случае она буферизуется по строкам.
Теперь, что я не понимаю, так это почему STDOUT
буферизуется за пределами цикла, отправленного в пайп, несмотря на то, что конечный пункт назначения — это терминал.
Простой пример :
$ while sleep 3; do echo -n "Текущее время: ";date +%T; done | mawk '{print $NF}'
^C
Ничего не происходит долгое время, потому что mawk
похоже накапливает свой вывод в буфере.
Я этого не ожидал. mawk
‘s вывод — это терминал, так зачем же его STDOUT
буферизуется?
Действительно, с опцией -Winteractive
вывод отображается каждые 3 секунды :
$ while sleep 3; do echo -n "Текущее время: ";date +%T; done | mawk -Winteractive '{print $NF}'
10:57:05
10:57:08
10:57:11
^C
Теперь это поведение явно связано с mawk
, потому что оно не воспроизводится, если я использую, например, grep
. Даже без опции --line-buffered
grep
не буферизует свой STDOUT
, что является ожидаемым поведением, учитывая, что grep
‘s STDOUT
— это терминал :
$ while sleep 3; do echo -n "Текущее время: ";date +%T; done | grep Current
Текущее время: 11:01:44
Текущее время: 11:01:47
Текущее время: 11:01:50
^C
Дело не в том, что он буферизует свой вывод.
mawk
— это единственная утилита, которую я знаю, которая буферизует свой ввод.
Смотрите также https://github.com/ThomasDickey/original-mawk/issues/41#issuecomment-241070898
Другими словами, mawk
не начнёт обрабатывать свой ввод (не говоря уже о том, чтобы что-то напечатать, если эта обработка включает печать), пока не накопит полный буфер ввода.
Вы можете проверить это, выполнив:
(echo 1; sleep 1; echo 2) | mawk '{system("echo "$1)}'
Это можно отключить с помощью опции -Winteractive
. Обратите внимание, что с -Winteractive
записи представляют собой строки, независимо от значения RS
.
просто делюсь своим опытом в Ubuntu
gawk
буферизация по строкам,
Не требуется никаких ухищрений
{ echo 1; sleep 1; echo 2; } | mawk '{print}'
mawk
работает только с -Winteractive
{ echo 1; sleep 2; echo 2; } | mawk -Winteractive '{print}'
эти трюки не работают:
- stdbuf -oL
- fflush()
- system(“”)
{ echo 1; sleep 1; echo 2; } | mawk '{print}'
{ echo 1; sleep 2; echo 2; } | mawk '{print; fflush(); system("");}'
{ echo 1; sleep 2; echo 2; } | stdbuf -oL mawk '{print}'
{ echo 1; sleep 2; echo 2; } | stdbuf -oL mawk '{print; fflush(); system("");}'
Ответ или решение
Почему стандартный вывод mawk имеет буферизацию, даже когда он направляется в терминал?
Когда мы работаем с командами в Unix-подобных системах, важно понимать, как обрабатывается ввод и вывод. В случае утилиты mawk
, стандартный вывод (STDOUT) может вести себя иначе, чем ожидается, особенно в ситуациях, когда вывод направляется в терминал. Давайте разберем это подробно.
1. Понимание буферизации в Unix
Буферизация — это механизм, используемый для повышения эффективности ввода-вывода. Обычно стандартный вывод программы буферизуется для повышения производительности. В случае mawk
, вы можете столкнуться с проблемой буферизации его стандартного вывода, когда вывод идет через конвейер (pipe). Эта буферизация происходит на уровне ввода в mawk
, что является основной причиной задержек в выводе.
2. Почему mawk буферизует ввод?
В отличие от большинства стандартных утилит, mawk
использует специфическую стратегию для обработки входных данных. Она накапливает данные во внутреннем буфере, прежде чем начать обработку. Это означает, что программа не будет выводить результаты, пока не соберет достаточно данных для обработки. В результате, даже если стандартный вывод в конечном итоге оказывается в терминале, вы не увидите результата до тех пор, пока mawk
не нашлет все накопленные данные в вывод.
3. Пример: Обработка данных с использованием pipeline
Рассмотрим пример:
while sleep 3; do echo -n "Current Time is "; date +%T; done | mawk '{print $NF}'
Здесь mawk
будет ждать, пока не накопит определенное количество записей во входном буфере, прежде чем начать вывод времени. Вы не увидите никакого вывода в терминале, пока не пройдет достаточно времени, чтобы mawk
собрал данные.
4. Сравнение с другими утилитами
В отличие от mawk
, такие утилиты, как grep
, не ведут себя подобным образом. Используя grep
, вы можете получить мгновенный вывод, даже без дополнительных опций, так как grep
сразу обрабатывает и выводит данные, когда они поступают на стандартный ввод.
5. Как изменить поведение mawk?
Чтобы отключить буферизацию во mawk
, вы можете использовать опцию -Winteractive
. Это заставит mawk
работать в интерактивном режиме, что позволяет ему немедленно выводить каждую строку при её поступлении:
while sleep 3; do echo -n "Current Time is "; date +%T; done | mawk -Winteractive '{print $NF}'
Таким образом, с данной опцией вывод будет происходить каждые три секунды, как и ожидалось.
Заключение
Буферизация ввода в mawk
является уникальной особенностью, которая может привести к неожиданному поведению, если не знать о ней. Понимание того, как именно работает каждая утилита, позволяет избежать путаницы и сделать ваше взаимодействие с инструментами Unix более предсказуемым. Использование опции -Winteractive
предоставляет контроль над выводом и обеспечивает то, чтобы результаты немедленно отображались на терминале.
Понять, как работают операционные системы и их инструменты, — это ключ к успешному управлению и оптимизации рабочих процессов в области IT.