我有一个 shell 脚本script.sh
,其中有一个在后台启动的命令cmd
,即:
#!/bin/bash
…
cmd &
…
如果我打开一个终端仿真器(我试过 xfce4-terminal 和 gnome-terminal)并script.sh
在其中运行,我的命令cmd
就会有效执行,并在后台执行,正如预期的那样。
但是,如果我从上一个终端仿真器(或者在我的桌面会话开始时,这是我的真实用例)打开一个终端仿真器,并通过以下方式执行我的脚本
xfce4-terminal -H -x script.sh (or gnome-terminal -x script.sh)
该命令cmd
不再执行。
我发现我可以通过将其放入我的脚本中来强制执行它set -m
,但我不明白为什么在这种情况下它是必要的(实际上也不是充分的),而在前一个情况下则不是。事实上,如果我将一个放入set -o
我的脚本中,我在两种情况下都会获得相同的输出。
有人可以向我解释这一点吗?或者告诉我在 shell 脚本中执行后台作业的正确方法吗?谢谢!
编辑:实际上,cmd
在两种情况下都会执行,但在第二种情况下,它会因 的终止而立即被终止script.sh
。为了防止这种情况,可以使用nohup
,但这还不够,这对我来说是最奇怪的事情:还必须放置sleep 1
或类似的东西,以允许进程在后台正确启动,并与父 shell 分离,否则它也会被终止。
我真的不明白这两个 shell 之间的行为差异,因为它们都是非交互式的,正如之前的评论所述。
答案1
如果您打开xfce4-trminal
或gnome-terminal
(或其他终端),您的 shell 处于交互模式。每个脚本都以交互模式运行。
如果你script.sh
跑过
xfce4-terminal -H -x script.sh
或者
gnome-terminal -x script.sh
或其他终端,您的shell处于非交互模式。
-i
可以使用选项或标头强制脚本以交互模式运行#!/bin/bash -i
。请注意,这可能会导致脚本行为不稳定或显示错误消息(即使没有错误)。
什么是set -m
?它是监控模式。后台进程在单独的进程组中运行,并在完成后打印一行包含其退出状态的信息。默认情况下,此功能对于交互式 shell 启用。
什么是set -o
?它将选项的当前设置以未指定的格式写入标准输出。
为什么set -o
有效?
−o 选项是从 KornShell 中采用的,以满足用户需求。除了其通常友好的界面外,−o 还需要提供 vi 命令行编辑模式,而历史上的实践并没有为该模式产生单字母选项名称。(虽然可能可以发明这样的字母,但人们认识到会开发其他编辑模式,并且 −o 提供了足够的名称空间来描述此类扩展。)
历史实现在用于 −o 选项状态报告的格式上不一致。添加了不带选项参数的 +o 格式,以允许可移植地访问可以保存然后稍后使用点脚本等恢复的选项。
无论如何,set -m
这是首选方式。
答案2
这个问题已在Unix Stackchange(另请参阅答案下方的其他评论)。这是一个谁向谁发送 SIGHUP 信号以及何时发送的问题。around in 的set -m / set +m
替代cmd &
方案script.sh
是trap '' HUP / trap - HUP
。