待機コマンドが失敗しました。

待機コマンドが失敗しました。

次のスクリプトには、この問題を説明する以外の目的はありません。

#!/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、2つの名前付きパイプを使用して、いくつかの(任意の)標準入力を2つのストリームに分割し、そのうちの1つを任意のパイプにリダイレクトし、結果として得られる2つのストリームの入力を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)。

おすすめ記事