cat을 통해 파이프하면 grep이 EOF까지 출력되지 않습니다


19

이 최소한의 예를 들어

( 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

이 일초 통과 할 때까지 출력이없고, 두 라인은 즉시 출력에 나타 나는 기대하지 않았다 .


왜 이런 일이 발생하며 마지막 세 버전을 처음 세 명령과 같은 방식으로 작동하게 할 수 있습니까?


cat파일을 연결합니다. 배관으로 무엇을하려고 cat합니까?
Douglas

15
@DouglasHeld 인수없이 호출되면 cat간단히 읽고 stdin출력합니다 stdout. 물론, 내가 대신 복잡한 물건의 많은이 질문에 내놓았다 echo하고 cat, 그러나이 최대 훨씬 간단 예제와 함께 문제 쇼 이후, 관련이없는 것으로 밝혀졌다.
lisyarus

3
@DouglasHeld : 고양이에게 배관하는 것은 종종 stdout이 터미널이되지 않도록하는 데 유용합니다. 예를 들어, 이것은 많은 명령을 사용하여 색상 화 된 출력을 사용하지 않는 쉬운 방법입니다.
wchargin

나는 이것이 Stack Overflow에 대한 또 다른 질문하나 라고 맹세합니다 !
iBug

@ wchargin 대단히 감사합니다, 당신은 나에게 내가 알지 못했던 posix에 대해 새로운 것을 가르쳐주었습니다.
Douglas

답변:


38

(적어도 GNU) grep의 출력이 터미널이 아닌 경우, 출력을 버퍼링하므로 현재보고있는 동작이 발생합니다. 이 중 하나를 사용하여 GNU 해제 할 수 grep--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

파이프에서 버퍼링 해제 에 대한 자세한 내용은이 항목을 참조하십시오.


26

단순화 된 설명

많은 유틸리티와 마찬가지로, 이것은 하나의 프로그램에 특유한 것이 아니며, grep표준 버퍼 출력을 라인 버퍼링완전히 버퍼링하는 것 사이 에서 변화 시킵니다. 전자의 경우, C 라이브러리 버퍼는 해당 데이터를 보유하는 버퍼가 채워지거나 줄 바꿈 문자가 추가되거나 프로그램이 완전히 종료 될 때까지 메모리에 출력 데이터를 write()버퍼링합니다. 후자의 경우에는 메모리 내 버퍼 만 가득 찼거나 프로그램이 완전히 종료됩니다 write().

더 자세한 설명

이것은 잘 알려져 있지만 약간 잘못된 설명입니다. 실제로 표준 출력은 라인 버퍼가 아니라 GNU C 라이브러리 및 BSD C 라이브러리에서 스마트 버퍼 됩니다. 표준 출력은 또한 표준 읽을 때 플러시 입력하면 소모 (프리 판독 입력) 메모리 버퍼 및 C 라이브러리 호출하는 read()몇 가지 이상의 입력을 페치 하고 , 그것을 새로운 라인의 시작을 판독한다. (이것의 한 가지 이유는 다른 프로그램이 필터의 양쪽 끝에 연결되고 필터에 대한 쓰기와 읽기 사이를 번갈아 가며 줄 단위로 작동 할 수있을 때 교착 상태를 방지하기위한 것입니다. GNU의 "코 프로세스" awk예를 들어)

C 라이브러리 영향

grep그리고 다른 유틸리티는 표준 출력을 감지하는 것에 기반하여 C 언어로 프로그래밍의 정의 된 기능이기 때문에이를 수행하거나 더 엄격하게 사용하는 C 라이브러리가이를 수행합니다. 대화 형 장치가 아닌 경우 전체 버퍼링을 선택하고 그렇지 않으면 스마트 버퍼링을 선택합니다. 파이프는 대화식 장치가 아닌 것으로 간주됩니다. 최소한 Unix 및 Linux 환경에서 대화식 장치라는 정의는 본질적으로 isatty()관련 파일 설명자에 대한 호출을 반환하기 때문입니다.

전체 버퍼링을 비활성화하는 해결 방법

당신이 볼 수 있듯이이 결정을 변경하는 grep것과 같은 특유의 옵션이있는 일부 유틸리티 에는 --line-buffered이름이 잘못되어 있습니다. 그러나 실제로 사용할 수있는 필터 프로그램의 작은 부분은 실제로 그러한 옵션을 가지고 있습니다.

보다 일반적으로, C 라이브러리의 특정 내부를 파헤 치고 의사 결정을 변경하는 도구를 사용할 수 있습니다 (변경 될 프로그램이 set-UID이고 특정 C 라이브러리에 특정한 경우 보안 문제가 있음). 같은 프로그램을 C 언어의 상단에 작성 또는 계층) 또는 도구에 대한 ptybandage그것은 하지 않습니다 에, 프로그램의 내부를 변경하지만은 의사 터미널 표준 출력과 결정은 "대화"로 나온다 그래서 단순히 끼어 이것에 영향을 미칩니다.

추가 자료


1
"line buffered"라는 문구가 잘못된 경우 실제로는 오류가 grep아니라 기본 라이브러리 호출 인 setbuf/setvbuf 입니다. C 표준에 대한 신뢰할 수있는 온라인 참조는 모르지만 Linux 및 FreeBSD 매뉴얼 페이지와 POSIX 설명을 setvbuf"라인 버퍼링"이라고합니다. 그것의 상징 상수조차도입니다 _IOLBF.
ilkkachu

이제 더 잘 배웠습니다. 이 버퍼링 전략 GNU C 라이브러리 doco에 간략히 설명되어 있습니다. Laurent Bercot는이 문제에 대해보다 솔직합니다. 나도 언급했다.
JdeBP

나는 "당신의 기대가 잘못되었다"고 출력 버퍼링에 대한이 훌륭한 설명의 좋은 제목이라고 생각하지 않았습니다. 나는 그것을 제거하고 답변의 각 섹션에 대해 설명적인 제목을 추가했다는 것을 신경 쓰지 않기를 바랍니다.
Anthony G-

2
@ilkkachu C 표준은 실제로 "라인 버퍼링"을 사용합니다. 7.21.3 파일, 단락 3 : "스트림이 버퍼링되지 않은 경우 ... 스트림이 완전히 버퍼링 된 경우 ... 스트림이 라인 버퍼링 된 경우 문자는 호스트 환경에서 또는 호스트 환경으로 ... "실제로, C 표준은"line buffered "라는 정확한 문구를 5 번 사용합니다. 따라서 이것은 잘못된 이름이 아닙니다.
Andrew Henle

1
또한 여기에서 "스마트 버퍼링"이라고 설명 된 접근 방식은 C 표준이 "라인 버퍼링"이라고 설명하는 것처럼 보입니다. 특히, 줄 바꿈에서 버퍼를 플러시하는 것 외에도, "스트림이 라인 버퍼링 될 때 문자는 버퍼링되지 않은 스트림에서 [...] 입력이 요청 될 때 또는 블록으로 호스트 환경에서 또는 호스트 환경으로 전송됩니다. 호스트 환경에서 문자를 전송해야하는 라인 버퍼 스트림에서 입력을 요청했습니다. " 따라서 이것은 GNU 또는 BSD 기발한 것이 아니라 언어가 요구하는 것입니다.
존 볼린저

7

용도

grep --line-buffered

grep이 한 번에 두 줄 이상을 버퍼링하지 않도록합니다.

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.