我正在使用包含在后台启动的script.sh
命令的bash 脚本:cmd
#!/bin/bash
…
cmd &
…
如果我打开终端模拟器并运行script.sh
,cmd
则会按预期在后台正确执行。也就是说,虽然script.sh
已经结束,但cmd
继续在后台运行,PPID 1。
但是,如果我从前一个终端模拟器(或者在桌面会话开始时,这是我的真实用例)打开另一个终端模拟器(比方说 xfce4-terminal),并script.sh
执行
xfce4-terminal -H -x script.sh
cmd
不再正确执行:它被终止script.sh
。仅用于nohup
防止这种情况是不够的。我有义务sleep
在它后面加上一个命令,否则在与, 解除关联之前会因 ,cmd
的终止而被杀死。script.sh
cmd
我发现在后台正确执行的唯一方法是set -m
将script.sh
.为什么在这种情况下有必要,而不是在第一种情况下?为什么两种执行方式之间的行为存在差异script.sh
(以及因此cmd
)?
我假设,在第一种情况下,监视模式是不是set -o
已激活,正如通过输入可以看到的那样script.sh
。
答案1
您应该运行的进程将被和之间的信号cmd
杀死,任何包装器或其他东西将没有机会运行并产生任何效果。 (您可以使用 检查)SIGHUP
fork()
exec()
nohup
strace
nohup
在执行后台命令之前,您应该在父 shell 中设置SIGHUP
为(ignore),而不是;SIG_IGN
如果信号处理程序设置为“忽略”或“默认”,则该配置将通过fork()
和继承exec()
。例子:
#! /bin/sh
trap '' HUP # ignore SIGHUP
xclock &
trap - HUP # back to default
或者:
#! /bin/sh
(trap '' HUP; xclock &)
如果使用 运行此脚本xfce4-terminal -H -x script.sh
,则后台命令 ( ) 不会被终止时发送的xclock &
命令杀死。SIGHUP
script.sh
当会话领导者(在您的情况下“拥有”控制终端的进程script.sh
)终止时,内核将从SIGHUP
其前景进程组;但set -m
将启用作业控制,并且以以下开头的命令&
将被放入背景进程组,并且它们不会通过 发出信号SIGHUP
。
如果未启用作业控制(非交互式脚本的默认设置),则以 开头的命令&
将在相同的前景进程组,“后台”模式将被伪造重定向他们的意见/dev/null
并让他们忽略 SIGINT
和SIGQUIT
。
进程以这种方式从曾经作为前台作业运行但已经退出的脚本发出信号SIGHUP
,因为它们的进程组(继承自已死亡的父进程)不再是终端上的前台进程。
额外说明:
xterm
和xfce4-terminal
(可能还有其他基于 vte 的终端)之间的“保持模式”似乎有所不同。虽然前者将使 pty 的主端保持打开状态,但后者将在程序运行-e
或-x
退出后将其撕下,导致对从端的任何写入失败并显示EIO
。当前台进程组中仍有进程运行时,xterm
也会忽略消息(即它不会关闭)。WM_DELETE_WINDOW
答案2
我一直在玩这个。我无法弄清楚,但这就是我发现的。我使用 sleep 3 作为我的命令。
这两个有效。我不知道ls
最后的作用是什么。括号和 double nohup
,它们构成了一个子过程(我认为这就是nohup
工作原理)。我不知道为什么nohup
它本身不起作用。
#!/bin/bash
nohup nohup sleep 3 &
ls #no idea why I need this
和
#!/bin/bash
(
nohup sleep 3 &
ls #no idea why I need this
)
/bin/true
代替 工作ls
。看来我们需要调用外部命令。还是不知道为什么。