Perché awk esegue il buffering completo quando legge da una pipe


23

Sto leggendo da una porta seriale collegata a un dispositivo gps che invia stringhe nmea.

Un'invocazione semplificata per illustrare il mio punto:

  $ 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

Se invece provo a leggere da una pipe, awk inserisce nel buffer l'input prima di inviarlo a 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

Come posso evitare il buffering?

Modifica : Kyle Jones ha suggerito che cat sta eseguendo il buffering del suo output ma ciò non sembra accadere:

$ 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

Quando ci penso: ho pensato che un programma utilizzava il buffering di linea quando scriveva su un terminale e il "buffering regolare" per tutti gli altri casi. Quindi, perché il gatto non sta tamponando di più? La porta seriale segnala EOF? Allora perché il gatto non è terminato?


1
BashFAQ 009 può essere utile.
— jw013

@ jw013: grazie per il link, un ottimo riassunto di come funziona il buffering in bash.
— Daniel Näslund

Risposte:


10

È probabile che sia buffering in awk, non in cat. Nel primo caso, awk ritiene che sia interattivo perché i suoi input e output sono TTY (anche se sono TTY diversi - immagino che awk non lo stia verificando). Nel secondo, l'input è una pipe, quindi viene eseguito in modo non interattivo.

Dovrai scaricare esplicitamente il tuo programma awk. Questo non è portatile, però.

Per ulteriori informazioni e dettagli su come scaricare l'output, leggi: http://www.gnu.org/software/gawk/manual/html_node/I_002fO-Functions.html


6
Grazie per la spiegazione. awk -W interactive '{print $0}'sembra fare il trucco. L' 'W interactiveopzione è disponibile sulla mia versione di awk (mawk 1.2) ma non so se è un'opzione standard.
— Daniel Näslund

1
@dannas -Wnon è nello standard POSIX perawk . Non sono sicuro di cosa fare se hai bisogno della massima portabilità.
— jw013

Sto accettando questa risposta poiché spiega perché awk sta eseguendo il buffering completo nel mio esempio, anziché il buffering di linea - controlla se l'input è un tty così come l'output. Ho solo pensato che avrebbe controllato l'output.
— Daniel Näslund

@ jw013: grazie per aver cercato lo standard. Per me, volevo solo capire perché Awk stava eseguendo il buffering completo e penso di farlo ora.
— Daniel Näslund,

@dannas Posso confermare che -W interactiveè almeno supportato nella distribuzione Ubuntu 12.04 (e presumibilmente più recente) di awk, che è mawk.
— Jason C,

37

So che è una vecchia domanda, ma un one-liner può aiutare coloro che vengono qui a cercare:

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

system("")fa il trucco ed è conforme a POSIX. Sistemi non posix: attenzione.

Esiste una funzione più specifica fflush()che fa lo stesso, ma non è disponibile nelle versioni precedenti di awk.

Un'importante informazione dai documenti riguardanti l'uso di system(""):

gawk considera questo uso della funzione system () come un caso speciale ed è abbastanza intelligente da non eseguire una shell (o un altro interprete di comandi) con il comando vuoto. Pertanto, con gawk, questo idioma non è solo utile, ma è anche efficiente.


Questo ha funzionato per me
— redolent il

3
Il mio awknon fa nulla su nessuno dei due fflush(), né system(""). L'ho gawkonorato però.
— Krzysztof Jabłoński,
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.