¿Por qué awk realiza un almacenamiento en búfer completo cuando lee desde una tubería?

23

Estoy leyendo desde un puerto serie conectado a un dispositivo GPS que envía cadenas nmea.

Una invocación simplificada para ilustrar mi 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

Si, en cambio, intento leer desde una tubería, awk almacena la entrada antes de enviarla 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

¿Cómo puedo evitar el almacenamiento en búfer?

Editar : Kyle Jones sugirió que cat está almacenando en búfer su salida, pero eso no parece estar sucediendo:

$ 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

Cuando lo pienso: pensé que un programa usaba el buffering de línea cuando escribía en una terminal y "buffering regular" para todos los demás casos. Entonces, ¿por qué el gato no está amortiguando más? ¿El puerto serie está señalizando EOF? Entonces, ¿por qué no se termina el gato?

Daniel Näslund
fuente
1
BashFAQ 009 puede ser útil.
jw013
@ jw013: Gracias por el enlace, un gran resumen de cómo funciona el almacenamiento en búfer en bash.
Daniel Näslund

Respuestas:

10

Es probable que esté almacenando en buffer en awk, no en cat. En el primer caso, awk cree que es interactivo porque su entrada y salida son TTY (a pesar de que son diferentes TTY, supongo que awk no está comprobando eso). En el segundo, la entrada es una tubería, por lo que se ejecuta de forma no interactiva.

Tendrá que vaciar explícitamente su programa awk. Sin embargo, esto no es portátil.

Para obtener más antecedentes y detalles sobre cómo vaciar la salida, lea: http://www.gnu.org/software/gawk/manual/html_node/I_002fO-Functions.html

camh
fuente
66
Gracias por la explicación. awk -W interactive '{print $0}'parece hacer el truco. La 'W interactiveopción está disponible en mi versión awk (mawk 1.2) pero no sé si es una opción estándar.
Daniel Näslund
1
@dannas -Wno está en el estándar POSIX paraawk . No estoy seguro de qué hacer si necesita la máxima portabilidad.
jw013
Estoy aceptando esta respuesta, ya que explica por qué awk está haciendo un búfer completo en mi ejemplo, en lugar de un búfer de línea: comprueba si la entrada es un tty y la salida. Solo pensé que verificaría la salida.
Daniel Näslund
@ jw013: Gracias por buscar el estándar. Para mí, solo quería entender por qué awk estaba haciendo buffering completo y creo que lo hago ahora.
Daniel Näslund
@dannas Puedo confirmar que -W interactiveal menos es compatible con la distribución Ubuntu 12.04 (y presumiblemente más nueva) de awk, que es mawk.
Jason C
37

Sé que es una vieja pregunta, pero una frase puede ayudar a aquellos que vienen a buscar:

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

system("")hace el truco y cumple con POSIX. Sistemas no posix: cuidado.

Existe una función más específica fflush()que hace lo mismo, pero no está disponible en versiones anteriores de awk.

Una información importante de los documentos sobre el uso de system(""):

gawk trata este uso de la función system () como un caso especial y es lo suficientemente inteligente como para no ejecutar un shell (u otro intérprete de comandos) con el comando vacío. Por lo tanto, con gawk, este idioma no solo es útil, sino que también es eficiente.

Shrein
fuente
Esto funcionó para mí
el aroma
3
Mi awkno hace nada ni fflush()tampoco system(""). Mi gawkhonrados que aunque.
Krzysztof Jabłoński