
아래 스크립트는 이 질문을 설명하는 것 외에는 다른 목적이 없습니다.
#!/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
. 개략적으로:
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
jordanm의 제안에 따라 파이프라인 주위에 중괄호를 추가했습니다 . (그래도 결과는 바뀌지 않았습니다.)- 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를 확인하기 전에는 완료되지 않습니다. stdin은 (및 해당 하위 항목이 있는 경우) 다른 쪽 끝에서 쓰는 파이프입니다 . 따라서 $pid
(및 하위 항목) 파이프의 쓰기 끝 부분까지 모든 파일 설명자(일반적으로 stdout만)를 닫을 때까지 eof를 볼 수 없습니다 . 명시적으로 stdout을 닫지 않는 한 $pid
(매우 드문 경우임) 이는 종료할 때만 발생합니다.
이것이 의미하는 바는 paste
대부분의 경우 이전에 종료하지 않는다는 뜻 입니다 $pid
. 만일의 경우에 대비해 여전히 좋은 생각입니다 wait
.
여기서는 coproc
임시 fifo를 피하기 위해 a를 사용할 수 있습니다.
coproc arbitrary_pipeline
cat >&p | paste - /dev/fd/3 3<&p &
coproc : close
wait
( wait
또한 coproc
s를 기다립니다).