我有一些后台作业运行的条件:
condition-command && condition-command && background-job &
问题是:我希望条件阻塞直到作业运行,就像我运行过一样:
condition-command; condition-command; background-job &
但这不是一个条件,如果前面的命令失败,我不希望该作业运行。
我意识到它是异步的,但它不应该,在我看来,以下两个脚本应该是相同的,但它们不是:
sleep 2; echo foo & sleep 1; echo bar; wait # prints foo, then bar: correct
sleep 2 && echo foo & sleep 1; echo bar; wait # prints bar, then foo: bug
我知道如果我测试$?
变量它会起作用,或者如果我将最后一个放在子shell中(但那样我会失去作业控制,我想避免守护进程),但我想知道为什么 bash 这样做,在哪里它有记录吗?有什么办法可以防止这种行为吗?
编辑:Chained if
s 很恶心,这就是为什么我不会接受它作为替代方式。
编辑2:我知道子 shell 是可能的,但它对我不起作用,让我们想象一下我最终想运行一堆命令wait
。如果我检查目录是否存在,这是可能的/proc/$PID
,但如果有多个工作,那就很麻烦了。
编辑3:主要问题是 bash 为什么这样做,它的文档在哪里?不管有没有解决方案都是一个奖励!
答案1
如果您不希望背景应用于整行,请使用eval
:
sleep 2 && eval 'sleep 10 &'
现在只有第二个命令是后台作业,并且它将是您可以wait
执行的正确后台作业。
答案2
编辑后:问题是 的&&
优先级高于&
,因此整个事物绑定在一起形成AND list
,并作为一个单元作为背景。看命令列表在手册中,虽然不是很清楚。
对原始代码进行的最小更改是
if condition-command && condition-command; then background-job & fi
(它是一个if
,但不是链式的)。
只是
condition-command && condition-command && (background-job &)
应该可以解决问题。
答案3
[这本质上是 jimmij 的评论,变成了答案。]
您可以使用它{ }
来覆盖正常的运算符优先级,而无需像( )
以前那样创建子 shell。所以使用:
condition-command && condition-command && { background-job & }
对于sleep
/echo
示例也类似:
sleep 2 && { echo foo & }; sleep 1; echo bar; wait # prints foo, then bar: correct
请注意,{
and}
是 shell 关键字,而不是像(
and 这样的元字符,因此您需要在其中的命令)
之间有一个空格(因此它不被视为命令名称的一部分),以及像或之前的命令终止符(因此它不被视为只是另一个论点)。另外,如果后面有另一个命令,则需要在它们之间使用分号(或其他命令分隔符)。{
&
;
}
}