linux命令setsid

Mat*_*vid 12 bash sessionid

我正在尝试编写一个包装器,它将脚本作为会话负责人执行.我对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
Run Code Online (Sandbox Code Playgroud)

输出因执行或来源而异:

$ 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
Run Code Online (Sandbox Code Playgroud)

所以,在我看来,setsid在脚本被源代码时立即返回,但是在脚本执行时它会等待它的子代.为什么控制tty的存在与之有关setsid?谢谢!

编辑:为了澄清,我将pid/ppid/sid报告添加到所有相关命令.

rua*_*akh 19

setsid实用程序的源代码实际上非常简单.你会注意到,只有fork()当它看到它的进程ID和进程组ID相等时(即,如果它看到它是一个进程组组长) - 并且它永远不会wait()用于它的子进程:如果fork()是,然后父进程立即返回.如果没有 fork(),那么它给出了wait()一个孩子的外表,但实际上发生的只是它孩子,而且它是Bash wait()(就像它一直一样).(当然,当它真的这样做时fork(),Bash不能wait()为它创造的孩子,因为wait()他们的孩子,而不是他们的孙子的过程.)

因此,您所看到的行为是不同行为的直接后果:

  • 当你运行. ./test.shor source ./test.sh或什么时 - 或者就此而言,当你setsid直接从Bash提示符运行时- Bash将setsid使用新的进程组ID 启动以进行作业控制,因此setsid将具有与其进程相同的进程ID- group-ID(也就是说,它是一个流程组负责人),所以它会fork(),也不会wait().
  • 当你运行./test.shor bash test.sh或whatnot并且它启动时setsid,setsid它将是与运行它的脚本相同的进程组的一部分,因此它的进程ID和进程组ID将是不同的,所以它不会fork(),所以它会给出等待的外观(实际上没有wait()).

  • 你是对的.我想知道是否值得建议`setsid`采取额外的标志,比如`-w`,如果有的话,它应该等待它的孩子.事实上,我觉得它的行为是不一致的:当且仅当它由一个组长(并且它分叉)运行时,它立即返回.另外,就像你说的那样,只有`setsid`可以等待它的孩子,调用`bash`不能等待孙子. (4认同)