Answers:
引用bash文档(来自man bash
):
JOB CONTROL
Job control refers to the ability to selectively stop
(suspend) the execution of processes and continue (resume)
their execution at a later point. A user typically employs
this facility via an interactive interface supplied jointly
by the operating system kernel's terminal driver and bash.
因此,简单地说,拥有set -m
(交互式shell的默认设置)允许使用诸如和fg
和的内置插件bg
,而这些内置插件将在set +m
(非交互式shell的默认设置)下禁用。
对我来说,作业控制和退出时杀死后台进程之间的联系并不明显,但是我可以确认有一个联系:set -m; (sleep 10 ; touch control-on) &
如果在键入该命令后立即退出shell,运行将创建该文件,但set +m; (sleep 10 ; touch control-off) &
不会。
我认为答案在于文档的其余部分set -m
:
-m Monitor mode. [...] Background pro‐
cesses run in a separate process group and a line con‐
taining their exit status is printed upon their comple‐
tion.
这意味着在其下启动的后台作业set +m
不是实际的“后台进程”(“后台进程是那些进程组ID与终端不同的进程”):它们与启动它们的Shell共享相同的进程组ID。流程组就像适当的后台流程。这解释了在外壳程序执行某些后台作业之前退出外壳程序时观察到的行为:如果我正确理解,则退出时,会向外壳程序所在的同一进程组中的进程发送信号(因此杀死在之下启动的后台作业set +m
),但不是到其他进程组的进程(因此,在之下不留下真正的后台进程set -m
)。
因此,根据您的情况,startup.sh
脚本大概会启动后台作业。当此脚本以非交互方式运行时(例如,在您链接的问题中通过SSH运行),则禁用了作业控制,“后台”作业共享了远程Shell的进程组,因此,一旦退出该Shell,就会被杀死。相反,通过在该外壳中启用作业控制,后台作业将获得其自己的进程组,并且在其父外壳退出时不会被杀死。
我在github问题列表中找到了这个,我认为这确实回答了您的问题。
这并不是一个真正的SSH问题,更多的是围绕BASH非交互/交互模式以及信号向进程组的传播的微妙行为。
以下内容基于 /programming/14679178/why-does-ssh-wait-for-my-subshells-without-t-and-kill-them-with-t/14866774#14866774 和http: //www.itp.uzh.ch/~dpotter/howto/daemonize,其中一些假设尚未得到充分验证,但是有关此工作原理的测试似乎可以证实。
pty / tty =错误
启动的bash shell连接到已启动进程的stdout / stderr / stdin,并保持运行状态,直到套接字上没有任何连接并且子进程退出为止。一个好的守护进程将确保它不会等待其子进程退出,派生一个子进程然后退出。在这种模式下,不会通过SSH将SIGHUP发送到子进程。我相信,这对于执行处理自我妖化过程的大多数脚本来说将是正确的,不需要后台处理。如果初始化脚本使用'&'来使进程后台运行,则主要问题可能是后台进程是否曾经尝试从stdin读取数据,因为如果会话已终止,这将触发SIGHUP。
pty / tty = true *
如果init脚本在后台启动了进程,则父BASH shell将向SSH连接返回退出代码,这将依次退出,因为它不等待子进程终止并且在stdout上未被阻止/ stderr / stdin。这将导致将SIGHUP发送到父bash shell进程组,由于在bash中以非交互模式禁用了作业控制,因此该组将包括刚刚启动的子进程。守护进程在分叉时或在分叉的进程中显式启动新的进程会话时,它或它的子进程将不会从退出的BASH父进程收到SIGHUP。请注意,这与将看到SIGTERM的暂停作业不同。我怀疑围绕此问题的问题有时仅与轻微的比赛条件有关。 http://www.itp.uzh.ch/~dpotter/howto/daemonize,您将在代码中看到新的会话是由派生的进程创建的,它可能在父级退出之前无法运行,从而导致随机上面提到的成功/失败行为。sleep语句将为分支过程创建新的会话留出足够的时间,这就是为什么它在某些情况下有效的原因。
pty / tty = true,作业控制已在bash中明确启用
SSH不会连接到bash shell的stdout / stderr / stdin或任何启动的子进程,这意味着它将在父bash shell开始完成执行所请求的命令后退出。在这种情况下,显式启用作业控制后,由bash shell启动并带有“&”作为背景的所有进程将立即置于一个单独的会话中,并且当BASH会话的父进程退出时,将不会收到SIGHUP信号( SSH连接)。
需要解决什么
我认为解决方案只需要在运行/ sudo操作文档中明确提及,作为使用后台进程/服务时的特殊情况。基本上使用'pty = false',或者在不可能的地方使用显式启用作业控制作为第一个命令,并且行为将是正确的。
tomcat/bin/startup.sh
与fg
/有bg
什么关系?