我正在尝试编写一个包装器,它将作为会话负责人执行脚本。
我对linux命令的行为感到困惑。考虑一下这个名为setsid
的脚本:
#!/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
因此,在我看来,
test.sh
在脚本获得源代码时立即返回,但它在脚本执行时等待其子脚本。为什么控制性tty的存在与
setsid
有关?谢谢!编辑:为了澄清,我向所有相关命令添加了pid/ppid/sid报告。
最佳答案
The source code of the setsid
utility实际上非常简单。您会注意到,只有当它看到它的进程ID和进程组ID相等时(即,如果它看到它是一个进程组负责人),它才会fork()
s,并且它的子进程永远不会wait()
s:如果它fork()
s,那么父进程就会立即返回。如果它不fork()
,那么它会给一个孩子带来wait()
ing的外观,但实际上发生的只是它是孩子,而Bash就是wait()
ing(就像它总是这样)。(当然,当Bash真正做到fork()
时,它不能为它创建的子进程wait()
,因为进程wait()
是为他们的子进程,而不是为他们的孙辈进程。)
所以你看到的行为是不同行为的直接结果:
当您运行. ./test.sh
或source ./test.sh
或其他操作时,或者当您直接从Bash提示符运行setsid
时,Bash将使用新的进程组ID启动setsid
,以便job control使用,因此setsid
将具有与其进程组ID相同的进程ID(即,它是进程组领导),因此它将fork()
而不会wait()
。
当您运行./test.sh
或bash test.sh
或其他操作时,当它启动setsid
时,setsid
将与运行它的脚本属于同一进程组,因此它的进程ID和进程组ID将不同,因此它不会fork()
,因此它将呈现等待的样子(实际上没有wait()
ing)。
关于bash - linux命令setsid,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/9677306/