我想在后台相继运行两个 shell 脚本,最好也使用nohup
.
我从
% nohup a.sh &
这a
在后台运行。
% nohup a.sh && nohup b.sh
运行a
然后b
(如果a
成功)
但如何在后台启动最后一个组合呢?
如果我做
% nohup a.sh && nohup b.sh &
a
将在前台运行,阻止提示符,然后b
在后台启动,将控制权返回给提示符。
% nohup a.sh & && nohup b.sh &
这给出了一个错误:zsh: parse error near '&&'
如何在后台启动两个进程?
答案1
这是 zsh 与 sh(或 csh)相比的已知偏差之一。
在sh中:
A && B &
是缩写:
(A && B) &
也就是说,它运行一个子 shell,该子 shell 在后台/异步运行该和/或列表。
在 zsh 中,
A && B &
同步运行A
,等待,如果成功,则B
在后台/异步运行。
那是其手册中注明(看info zsh list
):
A列表
;
是零个或多个子列表的序列,其中每个子列表以、&
、&|
、&!
或换行符终止。当列表作为复杂命令出现在(...)
或中时,可以选择从列表中的最后一个子列表中省略该终止符{...}
。当子列表由 或 换行符终止时;
,shell 会等待它完成,然后再执行下一个子列表。&
如果子列表以、&|
或终止&!
,则 shell 会在后台执行其中的最后一个管道,并且不会等待它完成(请注意与在后台执行整个子列表的其他 shell 的区别)。后台管道返回零状态。
(强调我的)。
和在常见问题解答中:
在zsh 中
cmd1 && cmd2 &
,仅cmd2
而不是整个表达式在后台运行。该手册暗示这是一个错误。用作{ cmd1 && cmd2 } &
解决方法。
A && B
要像其他 shell 一样在后台运行子 shell ,请使用:
(A && B) &
或者按照常见问题解答条目的建议:
{A && B} &
这是等效的,因为如果必须异步运行,我们无论如何都需要派生一个进程(并且主 shell 进程同时继续执行脚本的其余部分)。
所以在这里:
(nohup a.sh && nohup b.sh) &
不过,如果您只是希望运行该子 shell 的进程及其生成的其他进程不受 SIGHUP 信号的影响:
(trap '' HUP; A && B) &
(您还可以添加一些< /dev/null >> nohup.out 2>&1
以更接近地模仿 nohup)
相反,如果您希望在其他类似 sh 的 shell 中获得与 zsh 相同的行为:
A && { B & }
(请记住在 zsh 以外的 shell 中,当未启用作业控制时,异步运行的列表的 stdin 会重定向到 /dev/null)
1 偏差可能是无意的,因为之前文档的措辞2000 年进行的更改修复了它以符合实际行为(这可以追溯到 1990 年的 zsh 1.0)描述了 sh 行为。这也是常见问题解答的结论“手册暗示这是一个错误” 自1997年以来。但现在改变它已经太晚了(但有人认为应该在 sh、csh 或 ksh 模拟中改变它)。
答案2
您必须将这两个命令组合在一起:
nohup sh -c 'a.sh; b.sh' &
如果您只想在成功退出时运行,请替换;
为&&
b.sh
a.sh