为什么由 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 完成。