为什么双与号链接条件在后台与最后一个一起运行?

为什么双与号链接条件在后台与最后一个一起运行?

我有一些后台作业运行的条件:

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 ifs 很恶心,这就是为什么我不会接受它作为替代方式。
编辑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 这样的元字符,因此您需要在其中的命令)之间有一个空格(因此它不被视为命令名称的一部分),以及像或之前的命令终止符(因此它不被视为只是另一个论点)。另外,如果后面有另一个命令,则需要在它们之间使用分号(或其他命令分隔符)。{&;}}

相关内容