파이프에서 버퍼링 끄기 상황을 한 줄로 인쇄합니다). 문제 : stdout에

두 가지 명령을 호출하는 스크립트가 있습니다.

long_running_command | print_progress

long_running_command인쇄가 진행하지만 난 그게 불만입니다. 나는 print_progress그것을 더 멋지게 만들기 위해 사용 하고 있습니다 (즉, 진행 상황을 한 줄로 인쇄합니다).

문제 : stdout에 파이프를 연결하면 4K 버퍼가 활성화되어 멋진 인쇄 프로그램에 아무것도 얻지 못합니다 … 아무것도 … 아무것도 … 많은 … 🙂

4K 버퍼를 비활성화하려면 어떻게 long_running_command해야합니까 (아니요, 소스가 없습니다)?



답변

패키지의 unbuffer일부로 제공되는 명령을 사용할 수 있습니다.expect

unbuffer long_running_command | print_progress

unbufferlong_running_commandpseudoterminal (pty) 을 통해 연결 하여 시스템이 인터랙티브 프로세스로 취급하므로 지연의 원인이 될 수있는 파이프 라인에서 4-kiB 버퍼링을 사용하지 않습니다.

더 긴 파이프 라인의 경우 각 명령의 버퍼를 해제해야 할 수 있습니다 (최종 명령 제외).

unbuffer x | unbuffer -p y | z


답변

이 고양이를 스키닝하는 또 다른 방법 stdbuf은 GNU Coreutils의 일부인 프로그램 을 사용 하는 것입니다 (FreeBSD에는 자체 프로그램이 있습니다).

stdbuf -i0 -o0 -e0 command

입력, 출력 및 오류에 대한 버퍼링이 완전히 해제됩니다. 일부 응용 프로그램의 경우 성능상의 이유로 라인 버퍼링이 더 적합 할 수 있습니다.

stdbuf -oL -eL command

동적으로 연결된 응용 프로그램의 stdio버퍼링 ( printf(), fputs()…)에 대해서만 작동하며 , 해당 응용 프로그램이 표준 스트림 자체의 버퍼링을 자체적으로 조정하지 않는 경우에만 작동하지만 대부분의 응용 프로그램에 적용되어야합니다.


답변

에 대한 라인 버퍼링 출력 모드를 설정하는 또 다른 방법 은 의사 터미널 (pty)에서 실행 long_running_command되는 script명령 을 사용하는 것 long_running_command입니다.

script -q /dev/null long_running_command | print_progress      # FreeBSD, Mac OS X
script -c "long_running_command" /dev/null | print_progress    # Linux


답변

위해 grep, sed그리고 awk당신은 출력 라인 버퍼링을 강제 할 수 있습니다. 당신이 사용할 수있는:

grep --line-buffered

출력을 라인 버퍼링합니다. 기본적으로 출력은 표준 출력이 터미널 일 때 라인 버퍼링되고 다른 방식으로 블록 버퍼링됩니다.

sed -u

출력 라인을 버퍼링하십시오.

자세한 내용은이 페이지를 참조하십시오 :
http://www.perkin.org.uk/posts/how-to-fix-stdio-buffering.html


답변

출력이 터미널로 이동하지 않을 때 libc가 버퍼링 / 플러싱을 수정하는 데 문제가있는 경우 socat 을 시도해야합니다 . 거의 모든 종류의 I / O 메커니즘간에 양방향 스트림을 생성 할 수 있습니다. 그중 하나는 의사 tty에게 말하는 포크 ​​프로그램입니다.

 socat EXEC:long_running_command,pty,ctty STDIO 

그것이하는 일은

  • 의사 tty를 만들다
  • pty의 슬레이브 쪽이 stdin / stdout 인 fork long_running_command
  • pty의 마스터 측과 두 번째 주소 사이에 양방향 스트림을 설정하십시오 (여기서는 STDIO입니다)

이것이와 동일한 출력을 제공하면 long_running_command파이프를 계속 사용할 수 있습니다.

편집 : 와우 ​​언 버퍼 답변을 보지 못했습니다! 음, socat은 어쨌든 훌륭한 도구입니다.


답변

당신이 사용할 수있는

long_running_command 1>&2 |& print_progress

문제는 libc가 stdout을 화면에 올릴 때 라인 버퍼가되고 stdout이 파일을 볼 때 풀 버퍼가된다는 것입니다. 그러나 stderr에는 버퍼가 없습니다.

파이프 버퍼에 문제가 있다고 생각하지 않습니다 .libc의 버퍼 정책에 관한 것입니다.


답변

예전에는 표준 출력이 터미널에 쓰여질 때 기본적으로 라인 버퍼링됩니다-줄 바꿈이 쓰여질 때 줄이 터미널에 쓰여집니다. 표준 출력이 파이프로 전송되면 완전히 버퍼링되므로 표준 I / O 버퍼가 채워질 때 파이프 라인의 다음 프로세스로만 데이터가 전송됩니다.

그것이 문제의 원인입니다. 파이프에 쓰는 프로그램을 수정하지 않고 고칠 수있는 일이 많이 있는지 잘 모르겠습니다. 플래그 setvbuf()와 함께 함수를 사용하여 _IOLBF무조건 stdout라인 버퍼 모드로 전환 할 수 있습니다. 그러나 나는 그것을 프로그램에 적용하는 쉬운 방법을 보지 못한다. 또는 프로그램이 fflush()적절한 지점에서 (각 출력 행 후) 수행 할 수 있지만 동일한 주석이 적용됩니다.

파이프를 의사 터미널로 교체하면 표준 I / O 라이브러리는 출력이 터미널 (터미널 유형이기 때문에)이라고 생각하고 버퍼를 자동으로 라인 처리한다고 가정합니다. 그러나 그것은 사물을 다루는 복잡한 방법입니다.