다음 스크립트에는 이 문제를 설명하는 것 외에는 다른 목적이 없습니다.
#!/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
두 개의 명명된 파이프를 사용하여 일부(임의의) 표준 입력을 두 개의 스트림으로 분할하고 그 중 하나를 임의의 파이프로 리디렉션한 다음 결과 두 스트림의 입력을 paste
Schematic에 전달합니다.
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)
편집하다:
tee
Jordan의 제안에 따라 파이프 주위에 버팀대가 추가되었습니다. (그러나 결과는 변하지 않았습니다.)- 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
).