我正在尝试编写一个包装器,它将作为会话领导者执行脚本。我对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报告。
发布于 2012-03-13 22:24:42
The source code of the setsid utility实际上是非常简单的。您将注意到,它只有在发现自己的进程ID和进程组ID相等时才返回s(即,如果它看到自己是进程组领导者)-并且它从不为其子进程wait()s :如果它fork()s,则父进程将立即返回。如果它不是fork(),那么它看起来就像是一个孩子的wait()ing,但实际上发生的只是这个孩子,而Bash就是wait()ing (就像它总是做的那样)。(当然,当它真正执行fork()时,Bash不能为它创建的子进程执行wait(),因为它为他们的子进程处理wait(),而不是为他们的孙子进程。)
所以你看到的行为是不同行为的直接结果:
. ./test.sh或source ./test.sh或诸如此类的东西时-或者就此而言,当您直接从Bash提示符运行setsid时- Bash将使用一个新的进程组ID启动setsid以用于job control目的,因此setsid将具有与其进程组ID相同的进程ID(即,它是进程组领导者),因此它将运行而不会运行< fork() >d22或bash test.sh或诸如此类的,并启动setsid,等待将作为运行它的脚本的同一进程组的一部分,因此它的process-ID和process - setsid -ID将不同,所以它不会等待,所以它将显示为fork() (没有实际的等待发布于 2012-03-13 14:12:26
我不认为你的脚本有任何问题。我在代码中添加了额外的语句来查看发生了什么:
#!/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 相信我,运行这个修改过的脚本,你就会明白到底发生了什么。如果不是会话领导者的shell运行该脚本,那么它将直接转到else块。我是不是遗漏了什么?
我现在明白您的意思了:当您按原样对脚本执行./test.sh 1时,parent将等待孩子完成。子项阻止父项。但是如果你在后台启动了子进程,那么你会注意到父进程先于子进程完成。因此,只需在您的脚本中进行以下更改:
setsid bash test.sh &https://stackoverflow.com/questions/9677306
复制相似问题