在 Linux 系统上,bash 内置命令disown可用于从当前会话中删除作业。bash 是如何实现这个功能的呢?这里使用setsid()了,如果使用了,那么bash是如何触发子进程调用的呢setsid()?它使用信号吗?
小智 5
不会从当前会话 [1] 中删除作业,不会将其与终端分离,并且不会影响当会话领导者退出或控制终端被拆除时内核将发送哪些信号disown。
disown只适用于 bash 自己的作业表,只改变 bash 关于它所控制的作业的想法,并且只影响 bash 自己的行为,即它将重新发送SIGHUPbash 进程接收的作业。重新SIGHUP发送是 [2] 的一个额外功能bash,标准不要求,并且与操作系统提供的作业控制无关。
您可以通过一个简单的示例来查看它,我在其中script(1)创建一个 pty 并在其中运行一个交互式 shell 会话:
$ script /dev/null -qc bash
$ sh -c 'sleep 555 & sleep .1; kill -STOP $!; trap "echo hupped!" HUP; sleep 666' &
[1] 3837
$ disown -a
$ jobs
# no jobs known to bash
$ pgrep -as0
# show all processes from the current session
3836 bash
3837 sh -c sleep 555 & sleep .1; kill -STOP $!; trap "echo hupped!" HUP; sleep 666
3838 sleep 555
3841 sleep 666
$ kill -HUP $$
# seppuku the session leader
Hangup
hupped!
Run Code Online (Sandbox Code Playgroud)
这里,内核SIGHUP向后台进程组(=作业)发送一个信号,因为其中一个进程已停止,并且否认它不会阻止这种情况的发生。
来自的所有进程sh -c '...'都是同一作业的一部分,包括“后台” sleep &;默认情况下,shell 脚本不进行作业控制。
如果没有停止后台进程组的成员,则SIGHUP发送 no :
$ script /dev/null -qc bash
$ sh -c 'sleep 555 & trap "echo hupped!" HUP; sleep 666' &
[1] 3270
$ disown -a
$ kill -HUP $$
# sleep 555, 666 and sh -c are still running
Run Code Online (Sandbox Code Playgroud)
最后,bash 会SIGHUP向其表中的所有作业发送 a (仅那些由自身启动且未被拒绝的作业),无论 bash 是否是会话领导者,或者作业是否正在运行、停止等:
$ bash
$ sh -c 'sleep 555 & trap "echo hupped!" HUP; sleep 666' &
[1] 3413
$ kill -HUP $$
Hangup
hupped!
Hangup
Run Code Online (Sandbox Code Playgroud)
[1] 无论如何这是不可能做到的;只能将不是setsid()进程组领导者的进程创建为新会话,无法将整个作业移至新的或现有的会话中。
[2] 记录在 bash 的联机帮助页中:
shell 在收到
SIGHUP. 在退出之前,交互式 shell 会重新SIGHUP向所有正在运行或已停止的作业发送 。发送停止的作业SIGCONT以确保它们收到SIGHUP. 为了防止 shell 将信号发送到特定作业,应使用内置命令将其从作业表中删除disown(请参阅下面的 shell 内置命令)或SIGHUP使用标记为不接收disown -h。
还有一个shopt -s huponexit原因会导致登录bash shell 在退出时向其作业发送 a HUP(无论是否由于信号),这又以令人困惑的方式与操作系统的标准作业控制功能重叠。
| 归档时间: |
|
| 查看次数: |
1335 次 |
| 最近记录: |