Чому 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, а не кіт. У першому випадку awk вважає, що він є інтерактивним, оскільки його вхід і вихід - це TTY (навіть якщо вони різні TTY - я здогадуюсь, що awk цього не перевіряє). По-друге, вхід - це труба, тому вона працює неінтерактивно.

Вам потрібно буде чітко заграти у вашу програму awk. Це не портативно.

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


6
Дякую за пояснення. awk -W interactive '{print $0}'як видається, зробити трюк. Цей 'W interactiveваріант доступний у моїй версії awk (mawk 1.2), але я не знаю, якщо це стандартний варіант.
Даніель Наслунд

1
@dannas -Wне входить у стандарт POSIX дляawk . Я не впевнений, що робити, якщо вам потрібна максимальна портативність.
jw013

Я приймаю цю відповідь, оскільки вона пояснює, чому у моєму прикладі awk робить повну буферизацію замість буферизації рядків - вона перевіряє, чи є вхідний tty, а також вихідний. Я думав лише, що це перевірить вихід.
Даніель Наслунд

@ jw013: Дякуємо за пошук стандарту. Для мене я просто хотів зрозуміти, чому awk робив повний буфер, і я думаю, що зараз роблю.
Даніель Наслунд

@dannas Я можу підтвердити, що -W interactiveпринаймні підтримується в Ubuntu 12.04 (і, мабуть, новіший) розподіл awk, який є mawk.
Джейсон C

37

Я знаю, що це давнє питання, але однолінійний може допомогти тим, хто сюди приходить шукати:

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

system("")робить трюк і сумісний з POSIX. Системи без пошти: остерігайтеся.

Існує більш конкретна функція, fflush()яка робить те саме, але недоступна в старих версіях awk.

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

gawk трактує це використання функції system () як особливий випадок і досить розумний, щоб не запускати оболонку (або інший інтерпретатор команд) з порожньою командою. Тому з gawk ця ідіома є не тільки корисною, але й ефективною.


Це спрацювало для мене
повторне

3
Мій awkнічого не робить ні на ні, fflush()ні на system(""). Я gawkхоч і шанував це.
Кшиштоф Яблонський
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.