Почему awk выполняет полную буферизацию при чтении из канала?

23

Я читаю с последовательного порта, подключенного к устройству GPS, отправляя строки nmea.

Упрощенный вызов, чтобы проиллюстрировать мою точку зрения:

  $ awk '{ print $0 }' /dev/ttyPSC9 
  GPGGA,073651.000,6310.1043,N,01436.1539,E,1,07,1.0,340.2,M,33.3,M,,0000*56
  $GPGSA,A,3,28,22,09,27,01,19,17,,,,,,2.3,1.0,2.0*39
  $GPRMC,073651.000,A,6310.1043,N,01436.1539,E,0.42,163.42,070312,,,A*67
  GPGGA,073652.000,6310.1043,N,01436.1540,E,1,07,1.0,339.2,M,33.3,M,,0000*55
  $GPGSA,A,3,28,22,09,27,01,19,17,,,,,,2.3,1.0,2.0*39

Если я вместо этого попытаюсь прочитать из канала, awk буферизует ввод перед отправкой в ​​stdout.

$ cat /dev/ttyPSC9 | awk '{ print $0 }'
<long pause>
GPGGA,073651.000,6310.1043,N,01436.1539,E,1,07,1.0,340.2,M,33.3,M,,0000*56
$GPGSA,A,3,28,22,09,27,01,19,17,,,,,,2.3,1.0,2.0*39
$GPRMC,073651.000,A,6310.1043,N,01436.1539,E,0.42,163.42,070312,,,A*67
GPGGA,073652.000,6310.1043,N,01436.1540,E,1,07,1.0,339.2,M,33.3,M,,0000*55
$GPGSA,A,3,28,22,09,27,01,19,17,,,,,,2.3,1.0,2.0*39

Как я могу избежать буферизации?

Изменить : Кайл Джонс предположил, что кошка буферизирует свои выходные данные, но этого не происходит:

$ strace cat /dev/ttyPSC9 | awk '{ print $0 }'
write(1, "2,"..., 2)                    = 2
read(3, "E"..., 4096)                   = 1
write(1, "E"..., 1)                     = 1
read(3, ",0"..., 4096)                  = 2

Когда я думал об этом: я думал, что программа использовала буферизацию строки при записи в терминал и «обычную буферизацию» для всех других случаев. Тогда, почему кошка не буферизует больше? Сигнал последовательного порта EOF? Тогда почему кошка не прекращается?

Даниэль Нэслунд
источник
1
BashFAQ 009 может быть полезным.
jw013
@ jw013: Спасибо за ссылку, отличная оценка работы буферизации в bash.
Даниэль Нэслунд

Ответы:

10

Это скорее всего буферизация в awk, а не в cat. В первом случае awk считает, что он интерактивный, потому что его ввод и вывод - TTY (даже если они разные TTY - я предполагаю, что awk не проверяет это). Во втором вход является конвейером, поэтому он работает не в интерактивном режиме.

Вам нужно будет явно сбросить в вашей awk-программе. Это не портативно, хотя.

Дополнительную информацию и подробности о том, как очистить вывод, читайте по адресу : http://www.gnu.org/software/gawk/manual/html_node/I_002fO-Functions.html.

CAMH
источник
6
Спасибо за объяснение. awk -W interactive '{print $0}'кажется, чтобы сделать трюк. 'W interactiveОпция доступна на моей AWK версии (Мок 1,2) , но я не знаю , если это стандартный вариант.
Даниэль Нэслунд
1
@dannas -Wне входит в стандарт POSIX дляawk . Я не уверен, что делать, если вам нужна максимальная мобильность.
jw013
Я принимаю этот ответ, поскольку он объясняет, почему в моем примере awk выполняет полную буферизацию, а не буферизацию строки - он проверяет, является ли ввод tty, а также вывод. Я только думал, что это проверит вывод.
Даниэль Нэслунд
@ jw013: Спасибо за поиск стандарта. Для меня я просто хотел понять, почему awk делал полную буферизацию, и я думаю, что я делаю сейчас.
Даниэль Нэслунд
@dannas Я могу подтвердить, что -W interactive, по крайней мере, поддерживается в дистрибутиве Ubuntu 12.04 (и предположительно новее) awk, который называется mawk.
Джейсон С
37

Я знаю, что это старый вопрос, но однострочник может помочь тем, кто приходит сюда в поисках:

cat /dev/ttyPSC9 | awk '{ print $0; system("")}'

system("")делает трюк, и является POSIX-совместимым. Non-posix системы: будьте осторожны.

Существует более конкретная функция, fflush()которая делает то же самое, но недоступна в более старых версиях awk.

Важная информация из документов, касающаяся использования system(""):

gawk рассматривает это использование функции system () как особый случай и достаточно умен, чтобы не запускать оболочку (или другой интерпретатор команд) с пустой командой. Поэтому с gawk эта идиома не только полезна, но и эффективна.

Shrein
источник
Это сработало для меня
redolent
3
Мой awkничего не делает ни на, fflush()ни system(""). Мой gawkпочитал это все же.
Кшиштоф Яблонский