대기 명령이 실패했습니다.

대기 명령이 실패했습니다.

다음 스크립트에는 이 문제를 설명하는 것 외에는 다른 목적이 없습니다.

#!/usr/bin/env zsh

arbitrary_pipeline () {
    shuf | tr a-z A-Z
}

tmpdir=$( mktemp -d )

mkfifo $tmpdir/{orig,alt}

{ tee $tmpdir/orig | arbitrary_pipeline > $tmpdir/alt; } &
pid=$!

paste $tmpdir/orig $tmpdir/alt

rm -rf $tmpdir

wait $pid

스크립트는 tee두 개의 명명된 파이프를 사용하여 일부(임의의) 표준 입력을 두 개의 스트림으로 분할하고 그 중 하나를 임의의 파이프로 리디렉션한 다음 결과 두 스트림의 입력을 pasteSchematic에 전달합니다.

STDIN --- > --.- arbitrary_pipeline -.
               \                      \
          paste `----<FIRST-ARGUMENT>  `- <SECOND-ARGUMENT> --> STDOUT

(이 경우 arbitrary_pipeline표준 입력을 뒤섞어 대문자로 변환하지만 이름에서 알 수 있듯이 무엇이든 가능합니다.)

스크립트의 stdout 출력은 괜찮아 보이지만 wait명령은 항상 실패합니다.

% grep -iP 'z.*s.*h' /usr/share/dict/words | /tmp/test.sh
Nietzsche   CITIZENSHIP'S
Zubeneschamali  NIETZSCHE
Zubeneschamali's    ZUBENESCHAMALI
citizenship CITIZENSHIP
citizenship's   ZUBENESCHAMALI'S
/tmp/test.sh:wait:18: pid 26357 is not a child of this shell

내가 뭘 잘못했나요?


머리말:

/usr/bin/env zsh --version
# zsh 5.0.7 (x86_64-pc-linux-gnu)

편집하다:

  1. teeJordan의 제안에 따라 파이프 주위에 버팀대가 추가되었습니다. (그러나 결과는 변하지 않았습니다.)
  2. Stéphane Chazelas의 의견에 따라 &!대체 되었습니다 . &(이번에도 결과는 변함이 없습니다.)

답변1

5.0.8 이전에는 zsh죽은 작업을 기다릴 수 없었습니다. 이는 2014 5.0.8에서 변경되었습니다. 변경사항 보기거기.

/dev/null여기에서 stderr를 리디렉션하여 문제를 무시할 수 있습니다 .

wait $pid 2> /dev/null

다음 사항에 유의하세요.

{ tee $tmpdir/orig | arbitrary_pipeline > $tmpdir/alt; } &

최적화를 위해 zsh추가 프로세스가 포크되지 않으며 arbitrary_pipeline백그라운드에서 실행되는 서브셸을 실행하는 프로세스와 동일한 프로세스에서 실행됩니다.

paste$pid다른 쪽 끝에서 파이프(및 해당 하위 항목)가 기록되는 stdin에서 EOF를 볼 때까지 완료되지 않습니다 . 따라서 $pid(및 하위 항목) 파이프의 쓰기 끝 부분까지 모든 파일 설명자(보통 stdout)를 닫을 때까지 eof를 볼 수 없습니다 . 이는 $pid표준 출력이 명시적으로 닫히지 않는 한 종료 시에만 발생합니다(매우 드문 일입니다).

이는 대부분의 경우 paste만약을 대비해 그 전에 종료하지 않는 것이 $pid여전히 좋은 생각이라는 것을 의미합니다.wait

coproc여기에서는 다음을 사용하여 임시 FIFO를 피할 수 있습니다 .

coproc arbitrary_pipeline
cat >&p | paste - /dev/fd/3 3<&p &
coproc : close
wait

( wait아직 s 를 기다려야 한다는 점에 유의하세요 coproc).

관련 정보