通过 登录后ssh
,我在 中输入此命令bash
:
sleep 50000000000000 &
然后我kill -9
该sleep
进程的父进程(即bash
)。然后终端窗口同时断开连接。
当我再次登录时,发现该sleep
进程仍然存在。
问题:为什么sleep
我注销并关闭终端时,进程可以存活?在我的认知中,nohup
注销时除了守护进程和程序之外的所有进程都会被杀死。如果sleep
这样可以存活,是不是意味着我可以用这种方法代替命令nohup
?
答案1
总结:
为什么
sleep
我注销并关闭终端时,进程还能存活?我的想法是,nohup
注销时除了守护进程和程序之外的所有进程都会被杀死。如果sleep
这样都能存活,是不是意味着我可以用这种方法代替命令nohup
?
除非bash
由 生成的实例设置了ssh
选项huponexit
,否则在退出/注销时不会以任何方式终止任何进程,并且当huponexit
设置了选项时,kill -9
在 shell 上使用 并不是nohup
在 shell 的子进程上使用的一个好选择;nohup
在 shell 的子进程上仍然可以保护它们免受不是来自 shell 的 SIGHUP 的攻击,即使这并不重要,仍然nohup
是首选,因为它允许 shell 正常终止。
有bash
一个名为的选项huponexit
,如果设置了该选项bash
,在退出/注销时将使其子进程发出 SIGHUP 信号;
在互动未登录 bash
实例,例如bash
由 生成的实例gnome-terminal
,此选项将被忽略;无论是否huponexit
设置,bash
的子级在bash
退出时都不会被 SIGHUP 触发;
在互动登录 bash
实例,例如在bash
由 生成的实例中ssh
,此选项不会被忽略(但默认情况下未设置);如果huponexit
设置了,则在退出/注销时,bash
的子项将被 SIGHUP ;如果未设置,的子项在退出/注销时将不会被 SIGHUP ;bash
huponexit
bash
bash
因此,一般来说bash
,除非设置了该huponexit
选项,否则从交互式登录实例退出/注销不会使 shell SIGHUP 其子级,而从交互式非登录bash
实例退出/注销无论如何都不会使 shell SIGHUP 其子级;
然而,在这种情况下,这并不重要:kill -9
sleep
无论如何,使用都会存活下来,因为杀死它的父进程(bash
)不会给后者留下机会去做任何事物到前者(例如,如果当前bash
实例是登录bash
实例并且huponexit
设置了选项,则对其进行 SIGHUP)。
除此之外,与其他信号(例如发送到的SIGHUP信号bash
)不同,SIGKILL信号永远不会传播到进程的子进程,因此sleep
甚至不会被杀死;
nohup
启动一个不受 SIGHUP 信号影响的进程,这是不同的东西;它将阻止进程在接收到 SIGHUP 信号时挂断,在这种情况下,bash
如果huponexit
设置了选项并且退出了 shell,交互式登录实例可以接收到该信号;所以从技术上讲,在交互式登录实例中使用未设置选项nohup
来启动进程将阻止进程在接收到 SIGHUP 信号时挂断,但退出/注销 shell 无论如何都不会对其进行 SIGHUP ;bash
huponexit
然而,一般来说,当nohup
需要阻止来自父 shell 的 SIGHUP 信号时,没有理由优先使用kill -9
父方法而不是nohup
子方法;相反,应该相反。
使用 方法来终止父进程,kill -9
不会给父进程留下正常退出的机会,而使用nohup
方法来启动子进程,则允许父进程通过其他信号来终止,比如 SIGHUP(举一个在使用 启动的子进程的上下文中有意义的例子nohup
),这允许它正常退出。
答案2
bash
默认情况下退出时不向子进程发送 HUP 信号。更详细(感谢@kos),它从来没有这样做过非登录 shell。
您可以配置 bash 来执行此操作登录 shell如果设置了选项huponexit
。在终端中,执行以下操作:
[romano:~] % bash -l
(这将启动一个新的“登录”shell)
romano@pern:~$ shopt -s huponexit
romano@pern:~$ sleep 1234 &
[1] 32202
romano@pern:~$ exit
logout
现在检查该sleep
过程:
[romano:~] % ps augx | grep sleep
romano 32231 0.0 0.0 16000 2408 pts/11 S+ 15:23 0:00 grep sleep
...未运行:它已收到 HUP 信号并按请求退出。
答案3
如果
sleep
这样还能存活下来,是否意味着我可以用这个方法来代替nohup
命令呢?
kill -9
确实不是应该走的路。这就像用枪射击电视来关掉它。除了喜剧成分之外,没有任何好处。进程无法捕获或忽略SIGKILL
。如果您不给进程一个机会来完成它正在做的事情并进行清理,它可能会留下损坏的文件(或其他状态)并且无法重新启动。kill -9
当其他方法都不起作用时,这是最后的希望。
为什么当我注销并关闭终端时,睡眠进程还能存活下来。在我看来,注销时,除守护进程和 nohup 程序之外的所有程序都将被终止。
你的情况是这样的:
的父进程sleep
是当前正在运行的bash
shell。当您使用 bash 时,bash 进程没有机会向其任何子进程kill -9
发送,因为发送的无法被进程捕获。sleep 进程继续运行。sleep 现在变成了SIGHUP
SIGKILL
kill -9
孤儿进程。
init (PID 1) 进程执行一种称为“重新指定父进程”的机制。这意味着 init 进程现在成为该孤立进程的父进程。init 是一个例外,当它收集失去其原始父进程的进程时,进程可以成为它的子进程。顺便说一句:守护进程(如sshd
)在“进入后台”时会执行此操作。
如果不这样做,孤立进程稍后(完成后)将成为僵尸进程。这是在waitpid()
未调用时发生的情况(父进程的责任,当该进程被终止时无法履行)。 initwaitpid()
以特定的间隔调用以避免僵尸子进程。
答案4
使用&
将导致程序在后台运行。要查看后台程序,请使用bg
命令 ,要使其再次在前台运行,请运行fg
。
是的,即使主终端退出,也有很多方法可以让程序继续运行。