ksh는 파이프 오류를 어떻게 처리합니까?

ksh는 파이프 오류를 어떻게 처리합니까?

pipecommand.sh접두어와 PID 및 PPID를 인쇄하는 간단한 스크립트( )가 있습니다 .

#!/usr/bin/env ksh
echo "$1: PID $$  PPID $PPID" >&2

이 스크립트는 PID와 PPID를 인쇄하고 파이프를 생성합니다.

#!/usr/bin/env ksh
echo "S: PID $$  PPID $PPID"
./pipecommand.sh A | ./pipecommand.sh B

스크립트를 실행하면 다음과 같은 출력이 표시됩니다(PID를 단순화했습니다).

S: PID 11  PPID 22
B: PID 33  PPID 11
A: PID 44  PPID 11

좋아요, A와 B는 둘 다 쉘의 자식입니다. 말이 되네요. 때때로 A의 부모가 /sbin/upstart --user(적어도 우분투 16.10에서는) 있다는 것을 알았습니다 . 이상하지만 괜찮아요.

그러나 백그라운드에서 파이프라인을 실행하면(예 ./pipecommand.sh A | ./pipecommand.sh B &:) 다음과 같은 출력이 표시됩니다.

S: PID 11  PPID 22
B: PID 33  PPID 55
A: PID 44  PPID 33

좋습니다. B의 부모는 신생 기업입니다(PID 55). 그런데 A의 부모가 B인가요(아니면 이전처럼 무작위로 시작한 신생 기업인가요)? 어떻게 되어가나요? 이것은 버그입니까, 아니면 이런 일이 발생하는 이유를 설명하는 문서가 있습니까? 이는 SIGCHLD를 특정 방식으로 처리하는 프로그램에 특히 나쁜 것 같습니다(이것이 제가 이 문제를 겪게 된 방식입니다).

비교를 위해 bashA와 B의 첫 번째 경우는 shell의 자손이고, 두 번째 경우는 upstart의 자손입니다. 이러한 결과는 일관된 것으로 보입니다.

ksh --version나에게주세요: version sh (AT&T Research) 93u+ 2012-08-01.

답변1

ksh, Bourne 쉘과 같이 또는 yash비대화형인 경우 파이프에서 가장 오른쪽 명령만 기다립니다. 당신은 다음을 알게 될 것입니다 :

ksh -c 'sleep 1 | true'

즉시 그곳으로 돌아가세요.

귀하의 경우에는 시작 시 상위 프로세스가 이미 사라져서 변수를 채우기 위해 Aa를 수행 getppid()하고 아버지가 죽은 후 프로세스를 채택한 하위 프로세스의 pid 또는 하위 프로세스를 얻게 되는 경우가 있습니다 $PPID.init

이것은 실수가 아닙니다. 이는 선택에 따라 결정됩니다. 각 파이프라인 구성 요소를 기다리는 대신 이 작업을 수행하면 장점(대부분의 경우 성능 향상 등)과 불편함이 있습니다. 예를 들어 이와 같은 예상치 못한 동작이나 파이프라인 왼쪽의 명령이 파이프라인 스크립트 악용의 다음 명령입니다.

관련 정보