Warum puffert awk beim Lesen aus einer Pipe vollständig?

23

Ich lese von einem seriellen Port, der mit einem GPS-Gerät verbunden ist und nmea-Strings sendet.

Eine vereinfachte Aufforderung, um meinen Standpunkt zu veranschaulichen:

  $ 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

Wenn ich stattdessen versuche, aus einer Pipe zu lesen, puffert awk die Eingabe, bevor es an stdout gesendet wird.

$ 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

Wie kann ich die Pufferung vermeiden?

Edit : Kyle Jones schlug vor, dass Katze ihre Ausgabe puffert, aber das scheint nicht zu passieren:

$ 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

Wenn ich darüber nachdenke: Ich dachte, dass ein Programm beim Schreiben in ein Terminal die Zeilenpufferung und in allen anderen Fällen die "reguläre Pufferung" verwendet. Warum puffert die Katze dann nicht mehr? Signalisiert die serielle Schnittstelle EOF? Warum wird die Katze dann nicht gekündigt?

Daniel Näslund
quelle
1
BashFAQ 009 kann nützlich sein.
Jw013
@ jw013: Danke für den Link, eine großartige Zusammenfassung, wie das Puffern in Bash funktioniert.
Daniel Näslund

Antworten:

10

Es wird wahrscheinlich in awk gepuffert, nicht in cat. Im ersten Fall glaubt awk, dass es interaktiv ist, weil seine Eingabe und Ausgabe TTYs sind (obwohl sie unterschiedliche TTYs sind - ich vermute, dass awk das nicht überprüft). In der zweiten ist die Eingabe eine Pipe, sodass sie nicht interaktiv ausgeführt wird.

Sie müssen Ihr awk-Programm explizit einspülen. Dies ist jedoch nicht portabel.

Weitere Hintergrundinformationen und Details zum Leeren der Ausgabe finden Sie unter: http://www.gnu.org/software/gawk/manual/html_node/I_002fO-Functions.html

camh
quelle
6
Danke für die Erklärung. awk -W interactive '{print $0}'scheint den Trick zu tun. Die 'W interactiveOption ist in meiner awk-Version (mawk 1.2) verfügbar, aber ich weiß nicht, ob es eine Standardoption ist.
Daniel Näslund
1
@dannas -Wist nicht im POSIX-Standard fürawk . Ich bin mir nicht sicher, was ich tun soll, wenn Sie maximale Portabilität benötigen.
JW013
Ich akzeptiere diese Antwort, da hier erklärt wird, warum awk in meinem Beispiel die vollständige Pufferung anstelle der Zeilenpufferung vornimmt. Es wird geprüft, ob die Eingabe eine Zahl ist und die Ausgabe. Ich dachte nur, dass es die Ausgabe überprüfen würde.
Daniel Näslund
@ jw013: Danke, dass du den Standard nachgeschlagen hast. Für mich wollte ich nur verstehen, warum awk voll gepuffert hat, und ich denke, das tue ich jetzt.
Daniel Näslund,
@dannas Ich kann bestätigen, dass -W interactivezumindest die Ubuntu 12.04 (und vermutlich neuere) Distribution von awk unterstützt wird, die mawk ist.
Jason C
37

Ich weiß, es ist eine alte Frage, aber ein Einzeiler kann denjenigen helfen, die hierher kommen und suchen:

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

system("")macht den Trick und ist POSIX-konform. Nicht-Posix-Systeme: Vorsicht.

Es gibt eine spezifischere Funktion fflush(), die dasselbe tut, aber in älteren Versionen von awk nicht verfügbar ist.

Eine wichtige Information aus den Dokumenten bezüglich der Verwendung von system(""):

gawk behandelt diese Verwendung der system () -Funktion als Sonderfall und ist schlau genug, eine Shell (oder einen anderen Befehlsinterpreter) nicht mit dem leeren Befehl auszuführen. Daher ist diese Redewendung bei gawk nicht nur nützlich, sondern auch effizient.

Shrein
quelle
Das hat bei mir
geklappt
3
Ich awkmache nichts auf weder fflush()noch system(""). Ich habe es jedoch gawkgeehrt.
Krzysztof Jabłoński