セッションリーダーとしてスクリプトを実行するラッパーを作成しようとしています。 Linuxコマンドsetsid
の動作に混乱しています。 test.sh
と呼ばれるこのスクリプトについて考えてみます。
#!/bin/bash
SID=$(ps -p $$ --no-headers -o sid)
if [ $# -ge 1 -a $$ -ne $SID ] ; then
setsid bash test.sh
echo pid=$$ ppid=$PPID sid=$SID parent
else
sleep 2
echo pid=$$ ppid=$PPID sid=$SID child
sleep 2
fi
出力は、実行されるかソースされるかによって異なります。
$ bash
$ SID=$(ps -p $$ --no-headers -o sid)
$ echo pid=$$ ppid=$PPID sid=$SID
pid=9213 ppid=9104 sid= 9104
$ ./test.sh 1 ; sleep 5
pid=9326 ppid=9324 sid= 9326 child
pid=9324 ppid=9213 sid= 9104 parent
$ . ./test.sh 1 ; sleep 5
pid=9213 ppid=9104 sid= 9104 parent
pid=9336 ppid=1 sid= 9336 child
$ echo $BASH_VERSION
4.2.8(1)-release
$ exit
exit
したがって、スクリプトがソースされるとすぐにsetsid
が返されるように見えますが、スクリプトが実行されると子を待ちます。制御ttyの存在がsetsid
と関係があるのはなぜですか?ありがとう!
編集:明確にするために、関連するすべてのコマンドにpid/ppid/sidレポートを追加しました。
setsid
ユーティリティのソースコード は実際には非常に簡単です。プロセスIDとプロセスグループIDが等しいことを確認した場合(つまり、プロセスグループリーダーであることが確認した場合)はfork()
sのみであり、wait()
sの子プロセス:fork()
sの場合、親プロセスはすぐに戻ります。それがfork()
でない場合wait()
のように見えますが、実際には何が起こるかというと、それはが子であり、wait()
ingであるのはBashです(いつものように)。 (もちろん、実際にfork()
を実行する場合、Bashは作成した子に対してwait()
を実行できません。これは、孫ではなく子に対してwait()
を処理するためです。 )
したがって、表示されている動作は、別の動作の直接的な結果です。
. ./test.sh
_または_source ./test.sh
_などを実行すると、またはさらに言えば、Bashプロンプトから直接setsid
を実行すると、Bashは新しいsetsid
を起動します。 ジョブ制御 の目的でのprocess-group-ID、つまりsetsid
はそのprocess-group-IDと同じprocess-ID(つまり、プロセスグループリーダー)を持つので、 fork()
になり、wait()
にはなりません。./test.sh
_または_bash test.sh
_などを実行してsetsid
を起動すると、setsid
はそれを実行しているスクリプトと同じプロセスグループの一部になるため、そのプロセスは-IDとprocess-group-IDは異なるため、fork()
ではないため、待機しているように見えます(実際にはwait()
ingなし)。私が観察する行動は、あなたの行動とは異なりますが、私が期待するものです。使える set -x
あなたが物事を正しく見ていることを確認するために?
$ ./test.sh 1 子 親 $。 test.sh 1 child $ uname -r 3.1.10 $ echo $ BASH_VERSION 4.2.20(1)-リリース
実行時./test.sh 1
、スクリプトの親(インタラクティブシェル)はセッションリーダーであるため、$$ != $SID
そして条件は真です。
実行時. test.sh 1
、インタラクティブシェルはスクリプトをインプロセスで実行しており、独自のセッションリーダーであるため、$$ == $SID
であり、条件がfalseであるため、内部の子スクリプトを実行することはありません。
スクリプトに問題はありません。何が起こっているかを確認するために、コードにステートメントを追加しました。
#!/bin/bash
ps -H -o pid,ppid,sid,cmd
echo '$$' is $$
SID=`ps -p $$ --no-headers -o sid`
if [ $# -ge 1 -a $$ -ne $SID ] ; then
setsid bash test.sh
echo pid=$$ ppid=$PPID sid=$SID parent
else
sleep 2
echo pid=$$ ppid=$PPID sid=$SID child
sleep 2
fi
あなたに関係するケースは次のとおりです。
./test.sh 1
そして、私がこの変更されたスクリプトを実行すると信じてください。そうすれば、何が起こっているのかが正確にわかります。セッションリーダーではないシェルがスクリプトを実行する場合、それは単にelse
ブロックに移動します。私は何かが足りないのですか?
私は今あなたが何を意味するのかわかります:あなたがするとき./test.sh 1
スクリプトをそのまま使用すると、親は子が完了するのを待ちます。子は親をブロックします。ただし、子をバックグラウンドで開始すると、親が子の前に完了することに気付くでしょう。したがって、スクリプトに次の変更を加えるだけです。
setsid bash test.sh &