パイプから読み取るときにawkが完全なバッファリングを行う理由


23

nmea文字列を送信するgpsデバイスに接続されたシリアルポートから読み取ります。

私の要点を説明するための簡略化された呼び出し:

  $ 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

catではなくawkでバッファリングされる可能性があります。最初のケースでは、awkは入力と出力がTTYであるため(対話型であると考えています(TTYが異なっていても、awkはそれをチェックしていないと思います))。2番目では、入力はパイプであるため、非対話的に実行されます。

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はのPOSIX標準に-Wはありません。最大の移植性が必要な場合はどうすればよいかわかりません。awk
jw013

私の例では、行バッファリングの代わりにawkが完全なバッファリングを行う理由を説明しているため、この回答を受け入れています。入力だけでなく出力もttyであるかどうかをチェックします。出力をチェックするだけだと思った。
ダニエルネスランド

@ jw013:標準を調べてくれてありがとう。私にとっては、awkが完全なバッファリングを行っている理由を理解したかっただけで、今はそうしていると思います。
ダニエルネスランド

@dannas -W interactive少なくともUbuntu 12.04(おそらく新しい)のawkディストリビューション(mawk)でサポートされていることを確認できます。
ジェイソンC 14年

37

私はそれが古い質問であることを知っていますが、ワンライナーはここに来る人を探すのを助けるかもしれません:

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

system("")トリックを行い、POSIXに準拠しています。非POSIXシステム:注意してください。

fflush()同じことを行う、より具体的な機能が存在しますが、awkの古いバージョンでは使用できません。

の使用に関するドキュメントからの重要な情報system("")

gawkはこのsystem()関数の使用を特殊なケースとして扱い、空のコマンドでシェル(または他のコマンドインタープリター)を実行しないように十分スマートです。したがって、gawkでは、このイディオムは有用であるだけでなく、効率的でもあります。


これは私のために働いた
2014年

3
awkも何もしませfflush()system("")。私gawkはそれを光栄に思った。
クシシュトフヤウォウォスキ
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.