이 최소한의 예를 고려하면
( echo "LINE 1" ; sleep 1 ; echo "LINE 2" ; )
출력하고 LINE 1
1초 후에 LINE 2
,예상대로.
파이프로 연결하면grep LINE
( echo "LINE 1" ; sleep 1 ; echo "LINE 2" ; ) | grep LINE
동작은 이전 경우와 동일합니다.예상대로.
아니면 파이프로 연결하면cat
( echo "LINE 1" ; sleep 1 ; echo "LINE 2" ; ) | cat
행동은 또 똑같고,예상대로.
하지만, 로 파이프 grep LINE
한 다음 으로 파이프하면 cat
,
( echo "LINE 1" ; sleep 1 ; echo "LINE 2" ; ) | grep LINE | cat
1초가 지날 때까지 출력이 없으며 두 줄 모두 출력에 즉시 나타납니다.나는 기대가 없다.
왜 이런 일이 발생합니까? 마지막 버전이 처음 세 명령과 동일하게 작동하도록 하려면 어떻게 해야 합니까?
답변1
(적어도 GNU) grep
의 출력이 터미널이 아닌 경우 출력을 버퍼링하는데, 이것이 바로 여러분이 보고 있는 동작의 원인입니다. grep
GNU 옵션을 사용하여 이 기능을 비활성화 할 수 있습니다 --line-buffered
:
( echo "LINE 1" ; sleep 1 ; echo "LINE 2" ; ) | grep --line-buffered LINE | cat
또는 stdbuf
유틸리티:
( echo "LINE 1" ; sleep 1 ; echo "LINE 2" ; ) | stdbuf -oL grep LINE | cat
파이프라인에서 버퍼링 끄기이 주제에 대해서는 더 많은 내용이 있습니다.
답변2
간단한 설명
많은 유틸리티와 마찬가지로 이는 특정 프로그램에 특정한 것이 아닙니다 grep
.라인 버퍼그리고완전히 버퍼링됨. 전자의 경우 C 라이브러리는 이 데이터를 보유하는 버퍼가 채워지거나 개행 문자가 추가될 때까지(또는 프로그램이 완전히 종료될 때까지) 출력 데이터를 메모리에 버퍼링한 다음 write()
실제로 버퍼 내용을 쓰기 위해 호출됩니다 . 후자의 경우, 메모리 버퍼가 꽉 찼을 경우(또는 프로그램이 깔끔하게 종료될 경우)에만 실행됩니다 write()
.
자세한 설명
이것은 잘 알려져 있지만 약간 잘못된 해석이다. 실제로 표준 출력은 라인 버퍼링되지 않습니다.스마트 버퍼링GNU C 라이브러리와 BSD C 라이브러리에 있습니다. 표준 출력은반품표준을 읽을 때 얼굴이 붉어짐입력하다배기가스그것은메모리 버퍼(입력보다 먼저 읽기) 및 C 라이브러리는 read()
더 많은 입력을 얻기 위해 호출해야 함그리고새로운 줄의 시작 부분을 읽는 중입니다. (이에 대한 한 가지 이유는 다른 프로그램이 필터의 양쪽 끝에 연결되어 필터에 쓰는 것과 필터에서 읽는 것을 번갈아 가며 한 줄씩 작동할 수 있기를 원할 때 발생하는 교착 상태를 방지하기 위한 것입니다. GNU와 같습니다. ) 의 "코프로세스" awk
.
C 라이브러리 영향
grep
다른 유틸리티는 감지한 표준 출력, 더 엄밀히 말하면 이를 수행하는 데 사용하는 C 라이브러리를 기반으로 이 작업을 수행합니다. 이것이 C 프로그래밍의 정의 기능이기 때문입니다. 대화형 장치가 아닌 경우에는 전체 버퍼링을 선택하고, 그렇지 않은 경우에는 스마트 버퍼링을 선택합니다. 파이프는 대화형 장치로 간주되지 않습니다. 왜냐하면 적어도 Unix 및 Linux 세계에서는 대화형 장치의 정의가 기본적으로 isatty()
관련 파일 설명자에서 true를 반환하는 호출이기 때문입니다.
전체 버퍼링을 비활성화하는 해결 방법
일부 유틸리티에는 이 결정을 변경하는 옵션 grep
과 같은 특수 옵션이 있는데 --line-buffered
, 보시다시피 이름이 잘못되었습니다. 그러나 실제로 사용할 수 있는 필터링 프로그램 중 이러한 옵션을 제공하는 프로그램은 거의 없습니다.
보다 일반적으로 C 라이브러리의 특정 내부를 파헤쳐 결정을 변경하는 도구를 사용하는 것이 가능합니다. 변경하려는 프로그램이 set-UID이고 특정 C 라이브러리에만 해당되는 경우 보안 문제가 있습니다. , 그리고 이는) C로 작성되거나 C 위에 계층화된 프로그램 또는 유사한 ptybandage
도구 에만 해당됩니다.원하지 않는다프로그램의 내부 구조를 변경하되 단순히 의사 터미널을 표준 출력으로 삽입하여 결정이 "대화형" 형식으로 나타나도록 함으로써 이에 영향을 줍니다.
추가 읽기
답변3
사용
grep --line-buffered
grep이 한 번에 두 줄 이상을 버퍼링하지 않도록 합니다.