为什么setsid无法从Shell脚本退出?

3
$ cat test1.sh
#!/bin/bash

setsid sleep 100

'

'test1.sh' shell脚本将不会立即退出。

'
$ cat test2.sh
#!/bin/bash

setsid sleep 100 &

'

test2.sh' shell脚本会立即退出。

有人能帮我解释一下吗?非常感谢。

'

2
& 将命令放入后台,导致后续命令退出。 - devnull
1
请注意,这与setsid命令无关。 - chepner
"setsid"将使进程变为守护进程,因此我期望在执行"setsid sleep 100"后脚本会继续执行,而不是等待100秒。 - user3015856
2个回答

3

这个问题可能是这个更早的问题的重复,并且那里的答案非常有用。也许应该合并这些。

我对setsid的这种行为也感到惊讶。所以我查看了手册页面:

DESCRIPTION
       setsid runs a program in a new session. The command calls fork(2) if already a
       process group leader. Otherwise, it executes a program in the current process.
       This default behavior is possible to override by the --fork option.

这里有一些术语需要理解。让我们查看POSIX定义列表(第3章)。

会话是:

为了作业控制目的而建立的进程组的集合。每个进程组都是一个会话的成员。一个进程被认为是其进程组所属的会话的成员。新创建的进程加入其创建者的会话。进程可以更改其会话成员资格;参见 setsid()。同一个会话中可以有多个进程组。

fork()调用通过复制当前进程来创建一个新进程。更多信息请查看此帖子

进程组领导者是:

其进程ID与其进程组ID相同的进程。

所以,只有在作为进程组的领导者执行时,setsid才会创建一个新的进程。当直接在shell中运行命令时,这种情况总是发生的,以便可以将作业队列构建为进程组列表。然而,当作为脚本的一部分运行时,组长是用于运行脚本的新shell进程。
幸运的是,我们有--fork选项来强制创建一个新的进程。例如,shell脚本:
#!/bin/env bash
setsid --fork sleep 5

将在不等待sleep完成的情况下退出,并且即使关闭运行脚本的shell,sleep命令也会继续执行。据我所知,setsid --fork是确保命令作为独立进程运行的唯一方法

其他资源:


1
非常好的回答,但截至20230721,setsid不是posix shell工具的一部分:https://pubs.opengroup.org/onlinepubs/9699919799/utilities/contents.html。对我来说,`#!/usr/bin/env bash`看起来更好,因为posix没有规定安装工具的位置。 - Jay-Pi

0

你的第一个脚本等待setsid sleep 100执行完毕,然后返回(换句话说,在sleep完成后返回,这里是100秒),但第二个脚本不等待命令执行完毕,因为&将命令放在后台执行并立即返回。引用man bash的说法:

If  a  command is terminated by the control operator &, the shell executes the
command in the background in a subshell. The shell does not wait for the command
to finish, and the return status is 0.

还要注意的是,& 是一个控制运算符,它具有更高的优先级。希望这能帮到你!

谢谢您的回复。我知道在shell脚本中'&'的用法。如果去掉'setsid',您的答案非常好。但是这里使用了'setsid'。您能否从'setsid'的角度向我解释一下? - user3015856

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接