我退出后为什么我的进程仍在运行?

通过ssh ,我在bash输入以下命令:

 sleep 50000000000000 & 

然后我kill -9 sleep过程的父进程(即bash )。 然后终端窗口同时断开。

当我再次登录时,我发现sleep过程仍然存在。

问题 :当我退出并关闭终端时,为什么sleep过程能够存活? 在我看来,除了守护进程和nohup程序之外的所有东西都会在注销时被杀死。 如果sleep能够以这种方式存活,这是否意味着我可以使用此方法而不是nohup命令?

TL;博士:

当我退出并且终端关闭时,为什么sleep过程能够存活? 在我看来,除了守护进程和nohup程序之外的所有东西都会在注销时被杀死。 如果sleep能够以这种方式存活,这是否意味着我可以使用此方法而不是nohup命令?

除非ssh生成的bash实例设置了huponexit选项,否则在退出/退出时任何进程都不会终止任何进程,并且当设置huponexit选项时,在shell上使用kill -9不是使用nohup的好选择关于shell的子进程; 关于shell的子进程的nohup仍将保护它们不受来自shell的SIGHUP的影响,即使这不重要, nohup仍然是首选,因为它允许shell优雅地终止。


bash有一个名为huponexit的选项,如果设置将在退出/注销时将bash SIGHUP作为子huponexit ;

在交互式非登录 bash实例中,例如在gnome-terminal生成的bash实例中,忽略此选项; 无论huponexit是设置还是未设置, bash的子节点在退出时都不会受到bash影响;

在交互式登录 bash实例中,例如在ssh生成的bash实例中,不会忽略此选项(但默认情况下未设置此选项); 如果设置了huponexitbash的子节点将在退出/注销时被bash大写; 如果没有设置huponexit,退出/注销时bash的子节点不会被bash强行;

因此,通常从交互式登录bash实例退出/注销,除非设置了huponexit选项,否则不会使shell SIGHUP成为子huponexit ,并且从交互式非登录bash实例退出/注销将不会使shell成为shell无论如何,它的孩子都要大声说

然而,在这种情况下,这是无关紧要的:使用kill -9 sleep无论如何都会存活,因为杀死它的父进程( bash )不会让后者对前者做任何事情 (例如,如果当前bash实例是一个登录bash实例,并且huponexit选项已设置为SIGHUP()。

除此之外,与其他信号(如发送给bash的SIGHUP信号)不同,SIGKILL信号永远不会传播到进程的子进程,因此甚至不会杀死sleep ;

nohup启动一个免受SIGHUP信号影响的过程,这是不同的东西; 它会阻止进程在接收到SIGHUP信号时挂起,在这种情况下,如果设置了huponexit选项并退出shell,则交互式登录bash实例可以接收该信号; 因此,技术上使用nohup在交互式登录bash实例中启动进程并且huponexit设置huponexit选项将阻止进程在接收到SIGHUP信号时挂起,但是退出/退出shell将不会对其进行SIGHUP;

但是,一般情况下,当需要nohup来防止来自父shell的SIGHUP信号时,没有理由更喜欢父方法上的kill -9和子方法上的nohup ; 相反,它应该是相反的。

使用kill -9方法kill -9父级并不会让父级正常退出,而使用nohup方法启动子级允许父级被其他信号终止,例如SIGHUP(举个例子来说明在孩子的情境中感觉开始使用nohup ),这允许它优雅地退出。

默认情况下, bash 在退出时不会将HUP信号发送到子进程 。 更详细(谢谢@kos),它永远不会用于非登录shell 。

如果设置选项huponexit则可以配置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信号并按要求退出。

如果sleep可以通过这种方式存活,如果这意味着我可以使用此方法而不是nohup命令?

kill -9真的不是应该去的方式。 就像在电视机上用枪射击将其关闭一样。 除了喜剧成分之外没有任何优势。 进程无法捕获或忽略SIGKILL 。 如果你没有让进程有机会完成正在进行的操作和清理,它可能会留下损坏的文件(或其他状态),并且无法再次启动。 kill -9是最后的希望,没有别的办法。


当我退出并关闭终端时,为什么睡眠过程可以存活。 在我看来,除了守护进程和nohup程序之外的所有东西都会在注销时被杀死。

在你的情况下发生什么:

sleep的父进程是当前运行的bash shell。 当你kill -9那个bash时,bash进程没有机会向其任何子进程发送SIGHUP ,因为进程无法捕获SIGKILL (由kill -9发送)。 睡眠过程继续运行。 睡觉现在成了一个孤儿过程 。

init(PID 1)进程执行一种称为重新定位的机制。 这意味着init进程现在成为该孤立进程的父进程。 init是一个例外,进程可以成为它的子进程,因为它收集丢失原始父进程的进程。 顺便说一句:一个守护进程(如sshd )在“在后台进行”时sshd

如果不会发生这种情况,孤立的进程将在稍后(完成后)成为僵尸进程。 这是在未调用waitpid()时发生的情况waitpid()父进程的责任,当该进程被杀死时无法完成填充)。 init在特定的intervall中调用waitpid()以避免僵尸孩子。

&在后台启动该过程。 如果输入ps -ef ,您将看到睡眠的父进程ID(PPID)是您的bash。 然后注销并再次登录。 在您注销后,该过程将继续运行。 第二次登录后再次运行ps -ef 。 您将看到现在睡眠过程的父进程将以id为“1”进行处理。 这是init,所有进程的父级。

使用&将导致程序作为背景运行。 要在后台使用bg命令查看程序,并使其再次作为前台运行,请运行fg

是的,即使主终端退出,也有很多方法可以让程序保持运行。