为什么由 bash 脚本启动的进程在终端关闭后不会退出?
Why the process started by a bash script will not exit after the terminal has been closed?
案例一:
我在 gnome-terminal 中执行 sleep 1000 &
然后关闭终端。 sleep
进程不存在。
案例二:
这是一个脚本 t.sh
:
#!/usr/bin/env bash
sleep 1000 &
我在 gnome-terminal 中执行 ./t.sh
然后关闭终端。 sleep
进程存在(ps aux
已知)。进程不应该关闭吗?
简单来说,没有。使用“&”,您正在将当前进程设为 运行 作为后台进程。据我所知,你必须明确地杀死它。
使用交互式登录 shell 时,如果设置了此选项,bash 将在退出时向您的作业发送 HUP 信号:
juergen@samson:~ → shopt huponexit
huponexit on
默认处理程序将终止您的进程。当启动一个 non-interactive bash (就像你的脚本)时 huponexit 选项是无效的。参见:https://www.gnu.org/software/bash/manual/html_node/The-Shopt-Builtin.html
Jürgen Hötzel 在 中所说的是真实的,但事实并非如此。
案例 1:
当gnome-terminal
关闭时,tty(包括pty)驱动会得到tty的disconnect事件并发送SIGHUP
到控制与 tty 关联的进程。这里控制进程是bash,bash将接收SIGHUP
。然后,根据bash manual:
The shell exits by default upon receipt of a SIGHUP
. Before exiting, an interactive shell resends the SIGHUP
to all jobs, running or stopped. Stopped jobs are sent SIGCONT
to ensure that they receive the SIGHUP
.
If the huponexit
shell option has been set with shopt
, bash sends a SIGHUP
to all jobs when an interactive login shell exits.
所以对于情况 1,bash 将重新发送 SIGHUP
到后台作业 sleep
,它将被信号杀死(这是 SIGHUP
的默认行为).
(Jürgen Hötzel 提到的 huponexit
选项仅影响 交互式登录 shells 退出 自愿 。但是对于案例 1,bash 被 SIGHUP
杀死了。而且,bash running in gnome-terminal is not necessarily a login shell 虽然它确实是一个 交互式 shell.)
案例二:
这里涉及2个bash进程:
- bash#1: gnome-terminal 中 运行 的 bash 进程。
- bash#2:运行
t.sh
脚本的 bash 进程。
当 t.sh
(bash#2) 为 运行 时,sleep 1000 &
作为 bash#2 的后台作业启动。在 t.sh
(bash#2) 退出后,sleep
将继续 运行 但它将成为一个孤儿进程, init
进程将负责它和 sleep
的 PPID 将变为 1(init
进程的 PID)。
当 gnome 终端关闭时,bash#1 将收到 SIGHUP
并且 bash#1 将重新发送 SIGHUP
到它的所有作业。但是 sleep
不是 bash#1 的工作,所以 sleep
不会收到 SIGHUP
所以它将在 bash 之后继续 运行 #1 完成。
案例一:
我在 gnome-terminal 中执行 sleep 1000 &
然后关闭终端。 sleep
进程不存在。
案例二:
这是一个脚本 t.sh
:
#!/usr/bin/env bash
sleep 1000 &
我在 gnome-terminal 中执行 ./t.sh
然后关闭终端。 sleep
进程存在(ps aux
已知)。进程不应该关闭吗?
简单来说,没有。使用“&”,您正在将当前进程设为 运行 作为后台进程。据我所知,你必须明确地杀死它。
使用交互式登录 shell 时,如果设置了此选项,bash 将在退出时向您的作业发送 HUP 信号:
juergen@samson:~ → shopt huponexit
huponexit on
默认处理程序将终止您的进程。当启动一个 non-interactive bash (就像你的脚本)时 huponexit 选项是无效的。参见:https://www.gnu.org/software/bash/manual/html_node/The-Shopt-Builtin.html
Jürgen Hötzel 在
案例 1:
当gnome-terminal
关闭时,tty(包括pty)驱动会得到tty的disconnect事件并发送SIGHUP
到控制与 tty 关联的进程。这里控制进程是bash,bash将接收SIGHUP
。然后,根据bash manual:
The shell exits by default upon receipt of a
SIGHUP
. Before exiting, an interactive shell resends theSIGHUP
to all jobs, running or stopped. Stopped jobs are sentSIGCONT
to ensure that they receive theSIGHUP
.If the
huponexit
shell option has been set withshopt
, bash sends aSIGHUP
to all jobs when an interactive login shell exits.
所以对于情况 1,bash 将重新发送 SIGHUP
到后台作业 sleep
,它将被信号杀死(这是 SIGHUP
的默认行为).
(Jürgen Hötzel 提到的 huponexit
选项仅影响 交互式登录 shells 退出 自愿 。但是对于案例 1,bash 被 SIGHUP
杀死了。而且,bash running in gnome-terminal is not necessarily a login shell 虽然它确实是一个 交互式 shell.)
案例二:
这里涉及2个bash进程:
- bash#1: gnome-terminal 中 运行 的 bash 进程。
- bash#2:运行
t.sh
脚本的 bash 进程。
当 t.sh
(bash#2) 为 运行 时,sleep 1000 &
作为 bash#2 的后台作业启动。在 t.sh
(bash#2) 退出后,sleep
将继续 运行 但它将成为一个孤儿进程, init
进程将负责它和 sleep
的 PPID 将变为 1(init
进程的 PID)。
当 gnome 终端关闭时,bash#1 将收到 SIGHUP
并且 bash#1 将重新发送 SIGHUP
到它的所有作业。但是 sleep
不是 bash#1 的工作,所以 sleep
不会收到 SIGHUP
所以它将在 bash 之后继续 运行 #1 完成。