Por que o awk faz um buffer completo ao ler um pipe?

17

Estou lendo de uma porta serial conectada a um dispositivo GPS enviando strings nmea.

Uma invocação simplificada para ilustrar meu ponto:

  $ 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 eu, em vez disso, tentar ler de um pipe, o awk buffers a entrada antes de enviá-lo para 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

Como posso evitar o buffer?

Editar : Kyle Jones sugeriu que o gato está armazenando em buffer sua saída, mas isso não parece estar acontecendo:

$ 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 eu penso sobre isso: Eu pensei que um programa usado buffer de linha ao gravar em um terminal e "buffer regular" para todos os outros casos. Então, por que o gato não está armazenando mais? A porta serial está sinalizando o EOF? Então, por que o gato não é terminado?

    
por Daniel Näslund 07.03.2012 / 08:46

3 respostas

9

É provável que seja um buffer no awk, não no cat. No primeiro caso, o awk acredita que é interativo porque sua entrada e saída são TTYs (mesmo que sejam TTYs diferentes - suponho que o awk não está verificando isso). No segundo, a entrada é um pipe, portanto, ela é executada de forma não interativa.

Você precisará explicitamente liberar seu programa awk. Isso não é portátil, no entanto.

Para mais informações e detalhes sobre como liberar a saída, leia: link

    
por 07.03.2012 / 09:25
31

Eu sei que é uma pergunta antiga, mas uma frase de efeito pode ajudar aqueles que vêm aqui pesquisando:

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

system("") faz o truque e é compatível com POSIX. Sistemas não posix: cuidado.

Existe uma função mais específica fflush() que faz o mesmo, mas não está disponível em versões mais antigas do awk.

Uma informação importante de os documentos sobre o uso de system("") :

gawk treats this use of the system() function as a special case and is smart enough not to run a shell (or other command interpreter) with the empty command. Therefore, with gawk, this idiom is not only useful, it is also efficient.

    
por 21.07.2013 / 19:28
-1

É provavelmente cat armazenando sua saída. Use cat -u para desativar o buffer.

    
por 07.03.2012 / 08:57