kshはパイプエラーをどのように処理しますか?

kshはパイプエラーをどのように処理しますか?

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を特定の方法で処理するプログラムにとって特に悪いようです(これが私がこの問題に遭遇した方法です)。

比較のために、bashAとBの最初のケースはシェルの子孫であり、2番目のケースはupstartの子孫です。これらの結果は一貫しているようです。

ksh --version私にしてください: version sh (AT&T Research) 93u+ 2012-08-01

答え1

ksh、Bourneシェルのように、またはyash非対話型の場合は、パイプで一番右のコマンドだけを待ちます。あなたは次のことを知るでしょう:

ksh -c 'sleep 1 | true'

すぐにそこに戻ってください。

あなたの場合は、起動時に親プロセスがすでに消えて変数を埋めるためにAaを実行しgetppid()、父が死んだ後にプロセスを採用した子プロセスのpidまたは子プロセスを取得することがあります$PPIDinit

これは間違いではありません。これは選択によって決まります。各パイプラインコンポーネントを待つのではなく、これを行うことは利点(ほとんどの場合、パフォーマンスの向上など)と不便です。たとえば、このような予期しない動作やパイプラインの左側のコマンドは、パイプラインスクリプトの悪用の次のコマンドです。

関連情報