파이프에서 읽을 때 "sed q"가 다르게 작동하는 이유는 무엇입니까?

파이프에서 읽을 때 "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" 줄이 나타날 때까지 읽고 인쇄한 다음 중지합니다. 첫 번째 경우에는 cat이 나머지 내용을 읽고 인쇄하지만 두 번째 경우에는 그렇지 않습니다.

이러한 행동 차이 뒤에 숨어 있는 현상이 무엇인지 설명할 수 있는 사람이 있습니까?

또한 Ubuntu 16.04 및 Centos 6에서는 이런 방식으로 작동하지만 Centos 7에서는 두 명령 모두 "zzz"를 인쇄하지 않는 것으로 나타났습니다.

답변1

입력 파일이 다음과 같을 때탐색 가능한(일반 파일에서 읽는 것과 같은) 또는검색할 수 없음(파이프에서 읽는 것과 유사) sed(및 기타 표준 유틸리티)는 다르게 작동합니다 INPUT FILES.이 링크).

인용 문서:

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

그래서:

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

seduit 명령은 EOF에 도달하기 전에 실행 q되므로 줄의 시작 부분에 파일 오프셋을 남겨두고 나머지 줄을 계속 인쇄할 수 있습니다(GNU sed는 어떤 경우에는 POSIX와 호환되지 않습니다. 아래 참조) zzz.cat

그리고 문서를 계속 진행하면 다음과 같습니다.

검색 불가능한 파일의 경우 파일의 열린 파일 설명에 파일 오프셋 상태가 지정되지 않습니다.

이 경우 동작은 지정되지 않습니다. 대부분의 표준 도구(포함)는 sed가능한 한 많은 입력을 소비합니다. yyy라인 을 읽고 전달하며 q파일 오프셋을 복원하지 않으므로 아무것도 남지 않습니다 cat.


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

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

여기의 결과는 CEPH 백엔드가 있는 Openstack에서 실행되는 Mac OSX 10.11.6, 가상 머신 Centos 7.2 - glibc 2.17, Ubuntu 14.04 - glibc 2.19에서 얻은 것입니다.

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

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

파이프의 경우:

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

sed한 번에 한 바이트씩 읽어야 하므로 성능이 매우 비효율적입니다 . 부분 출력 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
...

관련 정보