cel*_*chk 704

让我们首先看看如果程序从没有&(也没有任何重定向)的交互式 shell(连接到终端)启动会发生什么。所以让我们假设你刚刚输入foo

  • 正在运行的进程foo已创建。
  • 该进程从shell 继承stdin、stdout 和stderr。因此它也连接到同一终端。
  • 如果 shell 接收到SIGHUP,它也会向SIGHUP进程发送一个(这通常会导致进程终止)。
  • 否则,shell 将等待(被阻止),直到进程终止或停止。

现在,让我们看看如果将进程置于后台会发生什么,即键入foo &

  • 正在运行的进程foo已创建。
  • 该进程从 shell 继承 stdout/stderr(因此它仍然写入终端)。
  • 该进程原则上也继承了 stdin,但是一旦它尝试从 stdin 读取,它就会停止。
  • 它被放入 shell 管理的后台作业列表中,这尤其意味着:
    • 它列出jobs并可以使用%n(其中n是作业编号)访问。
    • 可以使用 将其转换为前台作业fg,在这种情况下,它会继续,就好像您不会使用&它一样(如果由于尝试从标准输入读取而停止,它现在可以继续从终端读取)。
    • 如果外壳收到 a SIGHUP,它也会向SIGHUP进程发送 a 。根据外壳程序和可能为外壳程序设置的选项,在终止外壳程序时,它还会向SIGHUP进程发送 a 。

现在disown从外壳的作业列表中删除作业,因此上面的所有子点不再适用(包括SIGHUP外壳发送的进程)。但是请注意,它仍然连接到终端,所以如果终端被破坏(如果它是一个 pty,可能会发生这种情况,比如由xterm或创建的ssh,并且控制程序通过关闭 xterm 或终止SSH连接而终止) , 程序将在尝试从标准输入读取或写入标准输出时失败。

什么nohup呢,在另一方面,是有效地处理从所述终端分开:

  • 它关闭标准输入(程序将无法读取任何输入,即使它在前台运行。它不会停止,但会收到错误代码 或EOF)。
  • 它将标准输出和标准错误重定向到文件nohup.out,因此如果终端失败,程序不会失败写入标准输出,因此进程写入的任何内容都不会丢失。
  • 它阻止进程接收SIGHUP(因此名称)。

请注意,nohup不会从 shell 的作业控制中删除该进程,也不会将其置于后台(但由于前台nohup作业或多或少无用,您通常会使用 将其置于后台&)。例如,与 with 不同disown,shell 仍会告诉您 nohup 作业何时完成(当然,除非 shell 之前终止)。

所以总结一下:

  • & 将作业置于后台,即阻止它尝试读取输入,并使 shell 不等待其完成。
  • disown从 shell 的作业控制中删除进程,但它仍然保持连接到终端。结果之一是外壳不会向它发送SIGHUP. 显然,它只能应用于后台作业,因为在前台作业运行时您无法输入它。
  • nohup从端子断开过程,它的输出重定向到nohup.out和从屏蔽它SIGHUP。效果之一(命名效果)是该进程不会收到任何发送的SIGHUP. 它完全独立于作业控制,原则上也可用于前台作业(尽管这不是很有用)。

  • 如果同时使用这三者,该进程将在后台运行,从 shell 的作业控制中删除,并有效地与终端断开连接。 (25认同)
  • +1 谢谢。那么当同时使用 disown、nohup 和 & 时会发生什么? (13认同)
  • 也许值得包含`(foo&)`子shell (6认同)
  • 谢谢。我想知道为什么 [`nohup` 本身并不能避免 google-chrome 进程被关闭,当它启动的终端关闭时](http://unix.stackexchange.com/questions/162749/why-is -chromium-browser-killed-when-i-close-the-terminal-despite-nohup)? (3认同)
  • 如 https://unix.stackexchange.com/questions/446211/ 所述,`nohup` 与控制终端断开连接的观点是错误的。`nohup` 关闭一些标准 I/O 流并在其他地方打开它们。它不会更改会话,不会尝试影响会话与控制终端的连接,也不会处理进程组。 (3认同)
  • `disown %1` 和 `disown -h %1` 有什么区别?第二个将作为常规工作保留(但忽略 HUP 信号)直到终端退出? (2认同)
  • 请注意,如果进程使用自定义的 SIGHUP 句柄,nohup 将无法屏蔽 SIGHUP,因此可能无法清楚地将进程与 shell 隔离。所以将 disown 和 nohup 结合起来更安全。 (2认同)

Mic*_*zek 181

使用&会导致程序在后台运行,因此您将获得一个新的 shell 提示,而不是在程序结束之前阻塞。nohup并且disown基本上不相关;它们抑制 SIGHUP(挂断)信号,因此当控制终端关闭时程序不会自动终止。nohup在工作开始时执行此操作。如果您nohup在开始时没有工作,您可以使用disown修改正在运行的工作;没有参数它会修改当前的工作,这是刚刚背景的工作

  • `nohup` 和 `disown` 都可以说是抑制了 `SIGHUP`,但方式不同。`nohup` 使程序最初忽略信号(程序可能会改变它)。`nohup` 还尝试安排程序没有控制终端,以便在终端关闭时内核不会发送 `SIGHUP`。`disown` 纯粹是 shell 内部的;它会导致 shell 在终止时不发送 `SIGHUP`。 (207认同)
  • @Gilles,您的评论本身就值得一个答案。 (28认同)
  • nohup 和 disown 之间的细微差别:disown 命令会将其从您的作业列表中删除;nohup 不会。 (11认同)
  • 只是澄清@ShawnJ.Goff 的关于“disown”从工作列表中删除工作的评论。如果您不指定选项,它会将其从作业列表中删除。*然而*,如果你指定了`-h` 选项,每个jobspec **不会**从表中删除。相反,它使得如果 shell 接收到一个 SIGHUP 则不会将 SIGHUP 发送到作业。 (6认同)
  • 只是为了澄清,使用 `&` 不会给你一个终端,它会将 **`stdin`** 从进程中分离出来并使其在后台运行,但是 **`stdout`** 和 **`stderr `** 仍然附加到当前的 tty。这意味着您可能会将来自不同程序的文本混合在一起,如果您执行 `gimp &` 并且在尝试将该 tty 用于其他用途时遇到大量 GTK+ 错误,这可能会非常烦人。 (4认同)

Mar*_* An 19

这是我尝试在后台运行 soffice 的经验,遵循非终止命令(例如tail)。对于这个例子,我将使用sleep 100.

在下面的所有情况下,我都是这样执行的:

./scriptfile
<Ctl-C>
Run Code Online (Sandbox Code Playgroud)

&

#!/bin/bash
/opt/libreoffice4.4/program/soffice -invisible -nofirststartwizard &
sleep 100
Run Code Online (Sandbox Code Playgroud)

看到soffice日志/按Ctrl- Csoffice 停止

nohup .. &

#!/bin/bash
nohup /opt/libreoffice4.4/program/soffice -invisible -nofirststartwizard &
sleep 100
Run Code Online (Sandbox Code Playgroud)

没有看到soffice日志/按Ctrl- Csoffice 停止

&否认

#!/bin/bash
/opt/libreoffice4.4/program/soffice -invisible -nofirststartwizard & disown
sleep 100
Run Code Online (Sandbox Code Playgroud)

看到soffice日志/按Ctrl- Csoffice 停止

setsid .. &

#!/bin/bash
setsid /opt/libreoffice4.4/program/soffice -invisible -nofirststartwizard &
sleep 100
Run Code Online (Sandbox Code Playgroud)

看到soffice日志/按Ctrl- Csoffice不停止

为了节省空间:
nohup setsid ..:不显示日志/ soffice不会停止对Ctrl-C
nohup& disown底:不显示登录/ soffice在停止Ctrl-C

  • 虽然我很欣赏提到 setid 并展示在特定情况下会发生什么的努力,但我希望看到更彻底的答案。特别是每个解决方案的差异和相似之处,既可见(关闭外壳或终端时会发生什么,输出到哪里,...)和不可见(如何在引擎盖下完成及其影响)。接受的答案是一个很好的基础。 (3认同)
  • 对我来说,使用“nohup ⟨command⟩ &amp; disown”,创建的进程不会在“Ctrl+C”上停止。 (3认同)

iva*_*kov 18

简短回答:

  • 当您希望命令在后台运行时使用&,这样您就可以运行下一个命令而无需等待它完成
  • nohup如果您希望命令忽略信号,则使用SIGHUP,因此当您关闭终端或从 ssh 会话注销时,进程会继续运行
  • disown如果您忘记运行命令并且nohup想要注销而不终止进程(它将否认后台的所有进程),请使用。将进程置于后台并否认它:
    1. Ctrl+Z暂停进程
    2. bg将停止的进程置于后台
    3. disown使进程忽略终端终止