web-dev-qa-db-ja.com

Linuxコマンドsetsid

セッションリーダーとしてスクリプトを実行するラッパーを作成しようとしています。 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レポートを追加しました。

12
Matei David

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なし)。
19
ruakh

私が観察する行動は、あなたの行動とは異なりますが、私が期待するものです。使える 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であるため、内部の子スクリプトを実行することはありません。

1
ephemient

スクリプトに問題はありません。何が起こっているかを確認するために、コードにステートメントを追加しました。

    #!/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 &
0
Ankur Agarwal