bash 파이프 라인에서`yes`를 사용하면 왜 무한 루프가 발생합니까?


16

문서에 따르면 bash는 파이프 라인의 모든 명령이 실행을 마칠 때까지 기다렸다가 계속합니다.

쉘은 값을 리턴하기 전에 파이프 라인의 모든 명령이 종료되기를 기다립니다.

그렇다면 왜 명령 yes | true이 즉시 완료됩니까? yes루프를 영원히 유지 해서는 안되며 파이프 라인이 다시 반환되지 않아야합니까?


그리고 subquestion는 다음에 따라 POSIX 사양 , 쉘 파이프 라인은 명령이 완료 모든 때까지 마지막 명령이 완료 또는 대기 후 중 하나를 반환 할 수도 있습니다. 이런 의미에서 일반적인 쉘은 다른 동작을합니까? yes | true영원히 반복 되는 껍질이 있습니까?


yes | tee >(true) >/dev/nulltee모든 작가가 죽을 때까지 계속되는 것처럼 btw는 예상대로 수행 되므로 true종료해도 완전히 중단되지는 않습니다.
Charles Duffy

1
true기본적으로 {return 0;}프로그램이므로 영원히 혼자서는 물론 오랫동안 실행되지 않을 것입니다.
Dmitry Grigoryev

답변:


33

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를 통해 이벤트를보고 있는데, 먼저 오류와 함께 반환되는 시스템 호출 및 신호에 대해 알려줍니다. 에서 yes의 관점하지만, 먼저 신호가 발생합니다. 기술적으로 커널이 사용자 공간으로 제어를 리턴 한 후 더 많은 기계 명령어가 실행되기 전에 신호가 전달되므로 writeC 라이브러리 의 "래퍼 (wrapper)"기능이 설정 errno되어 애플리케이션으로 리턴 될 기회가 없습니다 .


1 안타깝게도 straceLinux에 따라 다릅니다. 대부분의 현대 유닉스는 비슷한 기능을 수행 하는 명령을 가지고 있지만 종종 다른 이름을 가지고 있으며 아마도 syscall 인수를 완전히 해독하지 않으며 때로는 루트에서만 작동합니다.


3
이 경우 @hugomg, 파이프는 전혀 관련이 없습니다.
muru

3
yes파이프에 연결된 것이 없기 때문에 @hugomg .
muru

4
사실, 그것은 "파이프 라인을 종료하기 전에 모든 명령이 끝날 때까지 기다리십시오"라는 문서화 된 행동을 보여줍니다. yes쓰고있는 FD가 파이프에 연결되어 있지 않기 때문에 SIGPIPE를 얻지 못하게 됩니다.
Tom Hunt

2
@hugomg, 그것은 영원히 반복되는 것과 같은 방식으로 yes >/dev/null영원히 반복됩니다. Tom은 종료 명령 동작이 간단한 명령에서도 마찬가지이기 때문에 간단한 명령에도 해당되지 않는 파이프 라인에 대해서는 전혀 설명하지 않습니다.
Charles Duffy

2
@zwol : 여기서 약간 다른 의미로 용어를 사용하거나 약간 다른 관점에서 사물을 생각하고 있다고 생각합니다. 그러나 어느 경우이든 write()(libc의 함수)는 이후까지 (제어를 PC에 넘겨줍니다) 반환하지 않습니다 신호 핸들러가 실행되었지만 신호 핸들러가 프로그램을 종료하므로 제어가 전송 write()되지 않으므로 리턴되지 않습니다. 그렇습니다. 커널에서 일부 xxx_write()함수 return 을 구현하여 구현 -EPIPE되었지만 사용자 공간 프로그램을 디버깅하고 관심이 없습니다.
Dietrich Epp

5

네 껍질이 있습니까? | 진실은 영원히 반복됩니까?

가능성은 이후 yes명령 파이프를 사용하고, 파이프가 파손되는 경우는 실패 할 것이다. sleep반면에 파이프를 사용하지 마십시오.

sleep 100000000 | true

적어도 100000000 초 동안 실행됩니다.


2
파이프에서 마지막 (가장 오른쪽) 내장 명령을 위해 분기되지 않는 모든 현대 쉘에주의하십시오 true. 이것은 최근 버전에 적용 Bourne Shell, ksh93, zsh. ^Z이러한 명령이 실행될 때 적중 하면 휴면 상태가 중단되고 쉘은 외부 도움 없이는 복구 할 수 없습니다.
schily

3
여기서 zsh 4.3.4 (i386-pc-solaris2.11)이므로 최근에 수정 된 것 같습니다. 흥미로운 생각, Bourne Shell에 대해 비슷한 수정을 구현할 수 있는지 살펴 봐야합니다. 어떻게 작동하는지, Bourne Shell에서와 같이 어떤 tty 프로세스 그룹이 사용되는지에 대한 의문이 여전히 남아 있습니다. 가장 긴 명령이 내장되어 있다는 사실은 수면 프로세스 그룹이 이미 설정된 후에 발견됩니다.
schily

2
@CharlesDuffy 내가 이해 한 것으로부터 schily는 sh의 버전을 유지하며, 그는 현대 쉘에서 개선 사항을 뒷받침합니다. 그는 여기 어딘가에 게시했습니다.
muru

3
가보 보관소의 Bourne Shell은 ~ 2007 년까지 유지 보수되었지만 아직까지 전화가 포함되어있어 완전히 휴대 할 수있는 것은 아닙니다 sbrk(). schily 도구 번들 및 @Charles 더피 이미 ;-) 정보의 위치를 발견에서 휴대용 유지 버전입니다
schily

2
@muru Bourne Shell로 백 포트 된 많은 기능은 저의 것입니다 bsh(UNOS의 가상 메모리 향상 버전 인 VBERTOS의 Berthhold Shell-첫 번째 UNIX 복제본). Bsh는 1984 년과 1985 년에 많은 csh 기능을 얻었지만 UNOS의 별칭 메커니즘은 1980 년 csh의 별칭 메커니즘보다 이미 우수했습니다. 다른 새로운 Bourne Shell 기능은 POSIX의 기능으로 POSIX 준수에 접근 할 수 있습니다.
schily
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.