nohup和ampersand有什么区别?

315

nohup myprocess.out &myprocess.out & 都可以让进程在后台运行。但是,当你关闭终端时,使用 nohup 命令的进程将不受 SIGHUP 信号的影响。


你使用的是哪个Shell?不同的Shell之间行为会有所不同。 - shx2
1
bash。现在我知道原因了,根据@nemo的回答。 - Yarkee
1
@Yarkee 如果答案解决了您的问题,请将问题标记为已接受(在答案投票下面的复选框中),这样它就不会作为未回答的问题悬而未决。您应该对所有问题都这样做 :) - nemo
1
应避免使用“shutdown”作为具有特定Linux含义的术语,应替换为“exit”。 - Patrizio Bertoni
7个回答

399

nohup 捕获hangup信号(参见man 7 signal),而ampersand则不会(除非shell已配置或根本未发送SIGHUP)。

通常,当使用&运行命令并在退出shell后,shell将使用hangup信号(kill -SIGHUP <pid>)终止子命令。可以使用nohup来防止这种情况,因为它捕获该信号并将其忽略,以使其永远不会达到实际应用程序。

如果您正在使用bash,则可以使用命令shopt | grep hupon查看您的shell是否向其子进程发送SIGHUP。如果关闭,进程将不会被终止,因为似乎是您的情况。有关bash如何终止应用程序的更多信息,请单击此处

有时nohup无法正常工作,例如您启动的进程重新连接SIGHUP信号,就像这里所述。


1
值得注意的是,仅使用 & 会导致子命令无法接收某些信号(例如 SIGINT)。nohup 实际上将 SIGHUP 添加到不传播的信号列表中。 - studgeek

75

myprocess.out &会在子shell中将进程在后台启动运行。如果当前shell被终止(例如通过注销),则所有子shell也会被终止,因此后台进程也将被终止。 nohup命令忽略HUP信号,因此即使当前shell被终止,子shell和myprocess.out仍将在后台继续运行。另一个区别是&本身不会重定向标准输出/错误输出,因此如果有任何输出或错误,它们将显示在终端上。另一方面,nohup将标准输出/错误输出重定向到nohup.out$ HOME / nohup.out


7
我使用命令 myprocess.out & 并退出了 shell。然而,当我在另一个 shell 中使用命令 ps aux | grep myprocess.out 时,我仍然可以找到 "myprocess.out"。这意味着该进程仍在运行,没有被终止。 - Yarkee
1
@amit_g 当使用 kill -9 杀死父 shell 时,不会有 SIGHUP 信号,因为这需要父 shell 处理 SIGKILL 信号,而它无法处理。 - nemo
3
请按照其他答案中提到的方式使用“Check shopt | grep hupon”命令。 - amit_g

54

大多数情况下,我们使用SSH登录远程服务器。如果你启动一个shell脚本并退出,则该进程将被终止。 Nohup可以帮助在你退出shell后继续在后台运行脚本。

Nohup command name &
eg: nohup sh script.sh &

Nohup捕获HUP信号。 Nohup不会自动将作业放在后台。我们需要明确地使用&来告诉它。


谢谢。没想到你会回答,但事实上这很棒。它回答了我没有问的问题:D - Vaibhav Kaushal

39
使用&符号会在子进程中运行命令(子进程是当前bash会话的子进程)。但是,当退出会话时,所有子进程都会被终止。
使用nohup + & 符号会做同样的事情,但是当会话结束时,子进程的父进程将被更改为“1”,即“init”进程,从而保护子进程不被杀死。

正如@Devender在下面的答案中指出的那样,只有在bash终端上设置了huponexit为“on”时才是正确的。 - SpinUp __ A Davis

10

如果我错了,请纠正我。

  nohup myprocess.out &

nohup可以捕获挂起信号,这意味着当终端关闭时它将继续运行进程。

 myprocess.out &

进程可以运行,但一旦终端关闭就会停止。

nohup myprocess.out

即使关闭终端,也可以运行进程,但您可以通过在终端中按ctrl+z来停止进程。 如果存在&,则ctrl+z无效。


1
从技术上讲,Ctrl+Z只是暂停了进程 - 您可以使用bg(后台)或fg(前台)恢复进程。 "停止"可能会被解释为无法恢复进程,因此可能会导致一些混淆。 - preOtep

6

nohup命令是一个信号屏蔽实用程序,用于捕获挂起(hangup)信号。而&符号不捕获挂起信号。使用&运行命令并退出shell时,shell将使用挂起信号终止子命令。可以通过使用nohup来防止这种情况发生,因为它可以捕获信号。Nohup命令接受挂起信号,可以通过内核发送到进程并阻止它们。当用户想要启动长时间运行的应用程序记录并注销或关闭启动该进程的窗口时,nohup命令非常有用。这些操作通常会提示内核停止应用程序,但nohup包装器将允许进程继续运行。 使用&符号将在一个子进程中运行命令,并在当前bash会话的子进程中运行。当您退出会话时,该进程的所有子进程都将被终止。&符号与活动shell的作业控制相关。这对于在后台运行会话中的进程非常有用。


5

有很多情况下环境之间的微小差异会给你带来麻烦。我最近就遇到了这样一种情况。这两个命令之间有什么区别?

1 ~ $ nohup myprocess.out &
2 ~ $ myprocess.out &

通常答案不变——依情况而定。

nohup捕获挂断信号,而&符号不会。

什么是挂断信号?

SIGHUP——检测到控制终端的挂断或控制进程的死亡(值:1)。

通常情况下,当使用&符号运行命令并在退出shell后,shell将使用挂断信号(如kill -SIGHUP $PID)终止子命令。可以使用nohup来防止这种情况发生,因为它捕获信号并忽略它,使其永远不会到达实际应用程序。

好的,但像在这种情况下总是有“但是”的。当shell未发送SIGHUP时,在配置了的方式下,这些启动方法之间没有区别。

如果您正在使用bash,则可以使用下面指定的命令来查找您的shell是否向其子进程发送SIGHUP:

~ $ shopt | grep hupon

此外,还有一些情况下 nohup 并不起作用。例如,当您启动的进程重新连接 NOHUP 信号时(这是在应用程序代码级别内完成的)。
在描述的情况下,当自定义服务启动脚本中调用第二个脚本以设置和启动适当的应用程序时,缺少区别使我受到困扰,而没有使用 nohup 命令。
在一个 Linux 环境中,一切都很顺利,而在第二个环境中,应用程序会在第二个脚本退出时立即退出(当然,要检测到这种情况比你想象的要花费更多的时间 :stuck_out_tongue:)。
在将 nohup 添加为第二个脚本的启动方法后,即使脚本退出,应用程序仍然保持运行状态,并且该行为在两个环境中变得一致。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接