当关闭终端时,nohup对后台进程是否产生影响?

8

nohup command & 可以在关闭终端后保持命令运行。

我想在 Music 目录中播放所有 mp3 音乐。

ls Music/*mp3 |xargs -d "\n" mplayer  

ls Music/*mp3 可以列出目录 Music 中的所有 mp3 文件,通过管道和 xargs 发送,-d "\n" 是为了处理文件名中的空格。

我希望将所有的 stdoutstderr 重定向到 /dev/null,并在后台运行。

ls Music/*mp3 |xargs -d "\n" mplayer > /dev/null 2>&1 &

这个程序目前可以正常工作,但我希望即便关闭终端窗口也能继续运行。

nohup ls Music/*mp3 | xargs -d "\n" mplayer > /dev/null 2>&1 &
ls Music/*mp3 | xargs -d "\n" nohup mplayer > /dev/null 2>&1 &
ls Music/*mp3 | nohup xargs -d "\n" mplayer > /dev/null 2>&1 &

当我关闭终端时,后台运行的进程也会结束。
为什么在以上三个命令中nohup不起作用?如何使其生效?
disown可以解决这个问题,但我想使用nohup来解决。
ls Music/*mp3 | xargs -d "\n" mplayer > /dev/null 2>&1 & disown

"disown" 相当于 "nohup",如何使用 "nohup" 来修复它? - showkey
在这种情况下,您需要在xargs之前加上nohup,因为当终端关闭时,是xargs接收到HUP信号。 - andreoss
xargs 前加上 nohup 是无效的。 - showkey
5个回答

9

nohup command 的意思是“运行 command 并忽略 HUP 信号”。因此,在我们有效地使用 nohup 之前,我们需要问:何时以及如何发送 SIGHUP?正如 Bash 手册所说的那样,“在退出之前,交互式 shell 会将 SIGHUP 重新发送给所有正在运行或停止的作业。”。它接着说,抑制这种行为的正确方法是使用 disown。我知道你在询问关于 nohup 的问题,但值得一提的是,disown 是实现你想要的目标的预期且更容易的方法。请注意,disown 不等同于 nohup

之所以在这里使用 nohup 很棘手,是因为它适用于单个进程,而 & 则创建了一个整个命令 作业 的后台 管道,其中可能包含多个进程。这意味着您需要为管道中的每个命令都使用 nohup,以确保各个命令不会接收到 SIGHUP,例如:

$ nohup ls Music/*mp3 2>/dev/null | nohup xargs -d "\n" nohup mplayer &> /dev/null &
< p >这个应该能行,但我还没有用这些具体命令进行过测试。如果不行,很可能是因为你没有直接启动的另一个进程仍然在接收SIGHUP信号。这更难以解决,正是我们拥有 disown 的原因。

manishg的建议也是合理的; 通过将管道移入单独的进程中,您可以nohup进程,从而防止SIGHUP传递到其子进程,当您的shell关闭时。


尽管如此,在这里您不需要使用lsxargs; 可以使用find来达到类似的效果,并简化命令的推理。尝试:

$ nohup find Music -maxdepth 1 -name '*mp3' -exec mplayer {} + &> /dev/null &

4
我想播放Music目录下所有的mp3音乐。
通常,您不需要使用ls或xargs。
您可以将整个流程简化为mplayer Music/*mp3 ✱。
这不仅对特殊文件名更加安全,而且还解决了您在nohup中遇到的问题。
nohup mplayer Music/*mp3 &> /dev/null &

✱ 只有一种情况下,此命令会失败,而 'ls * | xargs' 则成功。如果您有大量的 mp3 文件,可能会遇到命令行长度限制。该限制以字节为单位,由 'getconf ARG_MAX' 给出。在我的系统上,它是2097152,这意味着您需要至少8000个文件,假设最大文件名长度为255字节。对于较短的文件名,您可以拥有更多的文件。例如,如果您的 mp3 文件通常只有40个字节长,那么您可以使用超过44000个文件。

1

关闭终端有两种方法。
exit 方法:

在终端中输入 exit,然后点击 enter

交叉 方法:
点击右上角的 交叉

使用相同的png文件来说明它们。 enter image description here nohup 只能通过 exit 方法对所有以下命令生效(至少在终端中检查了三次)。

ls Music/*mp3 |xargs -d "\n" nohup mplayer  > /dev/null 2>&1 &
ls  Music/*mp3 | nohup  xargs  -d  "\n"  mplayer  > /dev/null  2>&1  &
nohup ls Music/*mp3 2>/dev/null | nohup xargs -d "\n" nohup mplayer &> /dev/null &
nohup find Music -maxdepth 1 -exec mplayer {} \; &> /dev/null &
nohup mplayer Music/*mp3 &> /dev/null &

对于 nohup sh -c nohup bash -c 都存在一个小 bug:

nohup sh -c 'ls  Music/*mp3 |  xargs  -d  "\n"  mplayer' &
[1] 4581
nohup: ignoring input and appending output to 'nohup.out'
nohup bash -c 'ls  Music/*mp3 |  xargs  -d  "\n"  mplayer' &
[1] 16831
nohup: ignoring input and appending output to 'nohup.out'

当使用“交叉”方式关闭终端时,上述命令的背景音乐将不会播放。

以“放弃”命令结尾的命令将继续以任何方式(“退出”或“交叉”方式)在后台播放音乐。
最好执行“disown”命令以在关闭终端后继续播放背景音乐。


1
点击角落的 x 可能会发送 SIGTERM 而不是 SIGHUP。nohup 的设计仅抑制 SIGHUP。 - dimo414
我认为nohup是更安全的选择,因为没有“优美的方式”来重新获取被放弃的进程。 - Furkan Küçük

0

您应该等待nohup将父进程转移到PID 1

$ nohup [YOUR COMMAND] 2>&1 &
nohup: appending output to 'nohup.out'
$ #usually this appeared then you can exit safely
$ sleep 1
$ exit

退出得太早可能会导致命令的父进程和它本身被杀死。

0

使用管道时,nohup 不会像这样工作。请使用以下方式:

nohup sh -c 'ls  Music/*mp3 |  xargs  -d  "\n"  mplayer' &

sh 在这个例子中应该能正常工作,但为了保持一致性,我建议使用 bash -c 而不是 sh -c。从 bash 脚本调用 sh 通常是意外的,并且有时是错误的。 - dimo414
nohup bash -c 'ls Music/*mp3 | xargs -d "\n" mplayer' & [1] 16831 - showkey
$ nohup: 忽略输入并将输出附加到 'nohup.out' - showkey

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