パイプから読み取るとawkが完全にバッファリングされるのはなぜですか?

パイプから読み取るとawkが完全にバッファリングされるのはなぜですか?

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

バッファリングを防ぐ方法は?

編集する:Kyle Jonesはcatが出力をバッファリングしていると提案しましたが、これは起こらないようです。

$ 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ですか?では、なぜ猫は終了しないのですか?

awkはmawk 1.2です。

答え1

私はこれが古い質問であることを知っていますが、ここでそれを探している人には、次の文が役に立つかもしれません。

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

system("")動作し、POSIXと互換性があります。 Non-posixシステム:注意してください。

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

重要なメッセージが来ます。文書使用情報system(""):

gawk は system() 関数のこれらの使用を特別なケースとして扱い、空のコマンドでシェル (または他のコマンドソルバー) を実行しないほどスマートです。したがって、gawkにとって、このイディオムは役に立つだけでなく効率的です。

答え2

おそらくcatではなくawkでバッファリングされているでしょう。最初のケースでは、awkは入力と出力がTTYであるためインタラクティブであると思います(たとえそれが異なるTTYであるにもかかわらず - awkはこれを確認しないようです)。 2番目の項目では、入力はパイプなので非対話型で実行されます。

awkプログラムで明示的に更新する必要があります。しかし、携帯性はありません。

出力を更新する方法の詳細な背景と詳細については、以下を参照してください。http://www.gnu.org/software/gawk/manual/html_node/I_002fO-Functions.html

答え3

古いトピックですが、魔法を使わずに透明な方法でストリームバッファリングの動作を変更するソリューションを追加する価値がありますsystem("")。 :-)

cat /dev/ttyPSC9 | stdbuf --output=L awk '{print $0}'

私は最近D-Busイベントをキャプチャするために直接使用しました。

gdbus monitor -y -d org.freedesktop.login1 | stdbuf -oL  grep LockedHint

関連情報