파이프에서 읽을 때 왜 ‘sed q’가 다르게 작동합니까?

다음을 포함하는 ‘test’라는 테스트 파일을 만들었습니다.

xxx
yyy
zzz

나는 명령을 실행했다 :

(sed '/y/ q'; echo aaa; cat) < test

그리고 나는 얻었다 :

xxx
yyy
aaa
zzz

그런 다음 나는 달렸다.

cat test | (sed '/y/ q'; echo aaa; cat)

그리고 얻었다 :

xxx
yyy
aaa

의문

sed‘y’가있는 줄이 나타날 때까지 읽고 인쇄 한 다음 중지합니다. 첫 번째 경우 (두 번째는 아님), 고양이는 나머지를 읽고 인쇄합니다.

누군가이 행동의 차이 뒤에 어떤 현상이 있는지 설명 할 수 있습니까?

또한 Ubuntu 16.04 및 Centos 6에서는이 방식으로 작동하지만 Centos 7에서는 명령이 ‘zzz’를 인쇄하지 않습니다.



답변

입력 파일 인 경우 시크 하거나 (일반 파일의 읽기와 같은) 되지 않은 시크 (파이프에서 읽기 등) sed(및 기타 표준 유틸리티) 다른 (읽기 동작합니다 INPUT FILES섹션 이 링크를 ).

문서에서 인용 :

표준 유틸리티가 탐색 가능한 입력 파일을 읽고 파일 끝에 도달하기 전에 오류없이 종료되는 경우, 유틸리티는 열린 파일 설명의 파일 오프셋이 유틸리티가 처리 한 마지막 바이트 바로 위에 위치하는지 확인해야합니다.

그래서 :

(sed '/y/ q'; echo aaa; cat) < test

sedqEOF에 도달하기 전에 uit 명령을 수행 하여 zzz줄의 시작 부분에서 파일 오프셋을 남겨 두어 나머지 줄 cat을 계속 인쇄 할 수 있습니다 (GNU sed는 어떤 조건에서 POSIX 호환이 아닙니다 (아래 참조)).

그리고 문서에서 계속 :

찾을 수없는 파일의 경우 해당 파일에 대한 열린 파일 설명의 파일 오프셋 상태는 지정되지 않습니다.

이 경우 동작은 지정되지 않습니다. 대부분의 표준 도구, 포함 sed은 가능한 한 많이 입력을 소비합니다. 파일 오프셋을 복원하지 않고 yyy행을 읽습니다 . q그래서 아무것도 남지 않습니다 cat.


GNU sed는 표준을 준수하지 않으며 시스템의 stdio 구현 및 glibc 버전에 따라 다릅니다.

$ (gsed '/y/ q'; echo aaa; cat) < test
xxx
yyy
aaa

여기서 결과는 Mac OSX 10.11.6, 가상 머신 Centos 7.2-glibc 2.17, Ubuntu 14.04-glibc 2.19에서 얻은 것으로, CEPH 백엔드를 사용하여 Openstack에서 실행됩니다.

이러한 시스템에서 -u옵션을 사용 하여 표준 동작을 달성 할 수 있습니다 .

(gsed -u '/y/ q'; echo aaa; cat) </tmp/test

그리고 파이프 :

$ cat test | (gsed -u '/y/ q'; echo aaa; cat)
xxx
yyy
aaa
zzz

sed번에 1 바이트를 읽어야 하기 때문에 성능이 크게 비효율적 입니다. 의 부분 출력 strace:

$ strace -fe read sh -c '{ sed -u "/y/q"; echo aaa; cat; } <test'
...
[pid  5248] read(3, "", 4096)           = 0
[pid  5248] read(0, "x", 1)             = 1
[pid  5248] read(0, "x", 1)             = 1
[pid  5248] read(0, "x", 1)             = 1
[pid  5248] read(0, "\n", 1)            = 1
xxx
[pid  5248] read(0, "y", 1)             = 1
[pid  5248] read(0, "y", 1)             = 1
[pid  5248] read(0, "y", 1)             = 1
[pid  5248] read(0, "\n", 1)            = 1
yyy
...


답변