Bash 파이프라인에서 "yes"를 사용하면 왜 무한 루프가 발생하지 *않나요*?

Bash 파이프라인에서 "yes"를 사용하면 왜 무한 루프가 발생하지 *않나요*?

문서에 따르면 bash는 계속하기 전에 파이프라인의 모든 명령 실행이 완료될 때까지 기다립니다.

셸은 값을 반환하기 전에 파이프라인의 모든 명령이 종료될 때까지 기다립니다.

그렇다면 명령이 yes | true즉시 완료되는 이유는 무엇입니까?yes영원히 반복되어 파이프가 절대 반환되지 않도록 해야 하지 않나요 ?


하위 질문도 있습니다.POSIX 사양, 셸 파이프라인은 마지막 명령이 완료된 후 반환하거나 모든 명령이 완료될 때까지 기다리도록 선택할 수 있습니다. 이런 의미에서 일반 쉘은 다르게 동작합니까? yes | true영원히 반복되는 쉘이 있습니까 ?

답변1

종료할 때 true파이프의 읽기 측이 닫히지만 yes쓰기 측에 대한 쓰기 시도는 계속됩니다. 이 상태를 "손상된 파이프"라고 하며 이로 인해 커널이 SIGPIPE. 이 신호는 특별한 처리가 이루어지지 yes않으므로 yes종료됩니다. 신호를 무시하면 write오류 코드와 함께 호출이 실패합니다 EPIPE. 이를 수행하는 프로그램은 주의를 기울이고 EPIPE쓰기를 중지할 준비가 되어 있어야 합니다. 그렇지 않으면 무한 루프에 빠지게 됩니다.

strace yes | true1을 수행하면 커널이 두 가지 가능성에 대해 자체적으로 준비하는 것을 볼 수 있습니다.

write(1, "y\ny\ny\ny\ny\ny\ny\ny\ny\ny\ny\ny\n"..., 4096) = -1 EPIPE (Broken pipe)
--- SIGPIPE {si_signo=SIGPIPE, si_code=SI_USER, si_pid=17556, si_uid=1000} ---
+++ killed by SIGPIPE +++

strace디버거 API를 통해 이벤트를 모니터링합니다. 이 API는 먼저 시스템 호출이 오류를 반환했음을 알려주고 신호를 알려줍니다. 그러나 관점에서 보면 yes신호가 먼저 발생합니다. (기술적으로 신호는 커널이 사용자 공간에 제어권을 반환한 후 더 많은 기계 명령이 실행되기 전에 전달되므로 C 라이브러리의 "래퍼" 기능은 설정되어 애플리케이션으로 반환될 write기회가 없습니다 .)errno


1안타깝게도 이는 straceLinux에만 해당됩니다. 대부분의 현대 유닉스는일부이 명령은 유사한 작업을 수행하지만 일반적으로 이름이 다르고 시스템 호출 인수를 완전히 디코딩하지 못할 수 있으며 때로는 루트에서만 작동합니다.

답변2

yes | true가 영원히 반복되는 쉘이 있습니까?

yes명령이 파이프를 사용하고 있으므로 파이프가 손상되면 명령이 실패할 가능성은 거의 없습니다 . sleep반면에 파이프는 사용되지 않으므로 다음과 같습니다.

sleep 100000000 | true

최소 100000000초 동안 실행됩니다.

관련 정보