파이프에서 읽을 때 awk가 완전히 버퍼링되는 이유는 무엇입니까?

파이프에서 읽을 때 awk가 완전히 버퍼링되는 이유는 무엇입니까?

nmea 문자열을 보내는 GPS 장치에 연결된 직렬 포트에서 데이터를 읽고 있습니다.

내 요점을 설명하기 위한 간단한 호출은 다음과 같습니다.

  $ 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

파이프에서 읽으려고 하면 awk는 입력을 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

버퍼링을 방지하는 방법은 무엇입니까?

편집하다:Kyle Jones는 cat이 출력을 버퍼링하고 있다고 제안했지만 이런 일은 일어나지 않는 것 같습니다.

$ 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

생각해 보면 프로그램은 터미널에 쓸 때 라인 버퍼링을 사용하고 다른 모든 경우에는 "일반 버퍼링"을 사용하는 것 같습니다. 그렇다면 고양이는 왜 더 많은 버퍼링을 수행하지 않습니까? 직렬 포트 신호가 EOF입니까? 그렇다면 고양이는 왜 종료되지 않습니까?

awk것은 mawk 1.2입니다.

답변1

나는 이것이 오래된 질문이라는 것을 알고 있지만, 여기에서 그것을 찾는 사람들에게 다음 문장이 도움이 될 수 있습니다.

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

system("")작동하며 POSIX와 호환됩니다. Non-posix 시스템: 주의하세요.

동일한 작업을 수행하는 보다 구체적인 함수가 존재 fflush()하지만 이전 버전의 awk에서는 사용할 수 없습니다.

중요한 메시지가 옵니다.문서사용 정보 system(""):

gawk는 system() 함수의 이러한 사용을 특별한 경우로 처리하고 빈 명령으로 쉘(또는 다른 명령 해석기)을 실행하지 않을 만큼 똑똑합니다. 그러므로 gawk에게 이 관용구는 유용할 뿐만 아니라 효율적이기도 합니다.

답변2

아마도 cat이 아닌 awk로 버퍼링되어 있을 것입니다. 첫 번째 경우 awk는 입력과 출력이 TTY이기 때문에 대화형이라고 생각합니다(비록 서로 다른 TTY임에도 불구하고 - awk는 이를 확인하지 않는 것 같습니다). 두 번째 항목에서는 입력이 파이프이므로 비대화형으로 실행됩니다.

awk 프로그램에서 명시적으로 새로 고쳐야 합니다. 하지만 휴대성이 없습니다.

출력을 새로 고치는 방법에 대한 자세한 배경 및 세부 정보는 다음을 참조하세요.http://www.gnu.org/software/gawk/manual/html_node/I_002fO-Functions.html

답변3

오래된 주제이지만 마법을 사용하지 않고도 투명한 방식으로 스트림 버퍼링 동작을 변경하는 솔루션을 추가할 가치가 있습니다 system(""). :-)

cat /dev/ttyPSC9 | stdbuf --output=L awk '{print $0}'

저는 최근에 D-Bus 이벤트를 캡처하는 데 직접 사용했습니다.

gdbus monitor -y -d org.freedesktop.login1 | stdbuf -oL  grep LockedHint

관련 정보