Pourquoi awk fait-il un tampon complet lors de la lecture d'un tube

23

Je lis depuis un port série connecté à un appareil GPS envoyant des chaînes nmea.

Une invocation simplifiée pour illustrer mon propos:

  $ 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

Si j'essaie plutôt de lire à partir d'un canal, awk met en mémoire tampon l'entrée avant de l'envoyer à 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

Comment éviter la mise en mémoire tampon?

Edit : Kyle Jones a suggéré que cat tamponne sa sortie mais cela ne semble pas se produire:

$ 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

Quand j'y pense: j'ai pensé qu'un programme utilisait la mise en mémoire tampon de ligne lors de l'écriture sur un terminal et la "mise en mémoire tampon régulière" pour tous les autres cas. Alors, pourquoi le chat ne tamponne-t-il pas plus? Le port série signale-t-il EOF? Alors pourquoi le chat n'est-il pas terminé?

Daniel Näslund
la source
1
BashFAQ 009 peut être utile.
jw013
@ jw013: Merci pour le lien, un bon résumé du fonctionnement de la mise en mémoire tampon dans bash.
Daniel Näslund

Réponses:

10

Il est susceptible de tamponner dans awk, pas dans cat. Dans le premier cas, awk pense qu'il est interactif car ses entrées et sorties sont des ATS (même si ce sont des ATS différents - je suppose que awk ne vérifie pas cela). Dans le second, l'entrée est un tube, donc elle s'exécute de manière non interactive.

Vous devrez vider explicitement votre programme awk. Ce n'est pas portable, cependant.

Pour plus d'informations et de détails sur la façon de vider la sortie, lisez: http://www.gnu.org/software/gawk/manual/html_node/I_002fO-Functions.html

camh
la source
6
Merci pour l'explication. awk -W interactive '{print $0}'semble faire l'affaire. L' 'W interactiveoption est disponible sur ma version awk (mawk 1.2) mais je ne sais pas si c'est une option standard.
Daniel Näslund
1
@dannas -Wn'est pas dans la norme POSIX pourawk . Je ne sais pas quoi faire si vous avez besoin d'une portabilité maximale.
jw013
J'accepte cette réponse car elle explique pourquoi awk fait une mise en mémoire tampon complète dans mon exemple, au lieu de la mise en mémoire tampon de ligne - il vérifie si l'entrée est un tty ainsi que la sortie. Je pensais seulement que cela vérifierait la sortie.
Daniel Näslund
@ jw013: Merci d'avoir recherché la norme. Pour moi, je voulais juste comprendre pourquoi awk faisait un tampon complet et je pense que je le fais maintenant.
Daniel Näslund
@dannas Je peux confirmer que -W interactivec'est au moins pris en charge dans la distribution Ubuntu 12.04 (et probablement plus récente) de awk, qui est mawk.
Jason C
37

Je sais que c'est une vieille question, mais un vol simple peut aider ceux qui viennent ici chercher:

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

system("")fait l'affaire et est compatible POSIX. Systèmes non posix: méfiez-vous.

Il existe une fonction plus spécifique fflush()qui fait de même, mais n'est pas disponible dans les anciennes versions d'awk.

Une information importante de la documentation concernant l'utilisation de system(""):

gawk traite cette utilisation de la fonction system () comme un cas spécial et est suffisamment intelligent pour ne pas exécuter un shell (ou un autre interpréteur de commandes) avec la commande vide. Par conséquent, avec gawk, cet idiome n'est pas seulement utile, il est également efficace.

Shrein
la source
Cela a fonctionné pour moi
renouvelé le
3
Mon awkne fait rien ni fflush()ni system(""). gawkMais je l' ai honoré.
Krzysztof Jabłoński