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
(少なくともUbuntu 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を特定の方法で処理するプログラムにとって特に悪いようです(これが私がこの問題に遭遇した方法です)。
比較のために、bash
AとBの最初のケースはシェルの子孫であり、2番目のケースはupstartの子孫です。これらの結果は一貫しているようです。
ksh --version
私にしてください: version sh (AT&T Research) 93u+ 2012-08-01
。
答え1
ksh
、Bourneシェルのように、またはyash
非対話型の場合は、パイプで一番右のコマンドだけを待ちます。あなたは次のことを知るでしょう:
ksh -c 'sleep 1 | true'
すぐにそこに戻ってください。
あなたの場合は、起動時に親プロセスがすでに消えて変数を埋めるためにA
aを実行しgetppid()
、父が死んだ後にプロセスを採用した子プロセスのpidまたは子プロセスを取得することがあります$PPID
。init
これは間違いではありません。これは選択によって決まります。各パイプラインコンポーネントを待つのではなく、これを行うことは利点(ほとんどの場合、パフォーマンスの向上など)と不便です。たとえば、このような予期しない動作やパイプラインの左側のコマンドは、パイプラインスクリプトの悪用の次のコマンドです。