有人可以解释一下为什么这个脚本
echo one &&
echo two &
echo three &&
echo four
给我
[1] 3692
three
four
one
two
[1]+ Done echo one && echo two
显然,后台进程后面的所有内容都会首先输出,然后按时间顺序打印后台进程之前的代码行。我在尝试编写的脚本中偶然发现了它,但不明白为什么它会这样(尽管我猜想它背后有一些独创性)。
我已经发现我可以用括号来防止这种情况:
echo one &&
(echo two &)
echo three &&
echo four
给出
one
two
three
four
和
echo one &&
(sleep 2 && echo two &)
echo three &&
echo four
给出
one
three
four
two
因为第二行在后台休眠,因此在第一行已经执行时输出。
但为什么括号会有这样的效果呢?
附加问题:为什么括号会阻止后台 PID 的输出?
答案1
echo one && echo two & echo three && echo four
请记住,这被解析为
echo one && echo two &
echo three && echo four
我假设这些echo
命令是成功的(它们只会在边缘情况下失败,例如重定向到完整磁盘上的文件)。因此,此代码片段并行运行两个任务:一个打印行one
和two
,另一个打印行three
和four
。one
和two
与three
和 的散布four
是不保证的,并且可能会因系统、shell 和调用的不同而有所不同。对于像这样的玩具示例,您可能会在轻负载系统上观察到可重现的结果,但这不是您可以指望的。
echo one && (echo two &) echo three && echo four
您已经更改了解析:这里只有命令echo two
在后台执行。这保证了将one
首先输出,并且像 before 一样three
将始终在 before four
,但 的位置two
可以在 after 的任何位置one
。
如果后台进程是从主 shell 进程启动的,则 shell 仅打印有关后台进程的消息,而当它们在子 shell 中启动时则不会。括号创建一个子 shell,这就是为什么(echo two &)
不会导致 shell 打印任何消息的原因。这会创建一个后台进程,但不是后台工作。
echo one && (sleep 2 && echo two &) echo three && echo four
在此代码片段中,后台作业在输出之前休眠 2 秒two
。这使得极有可能(但实际上不能保证)将在和two
后输出。three
four
答案2
第1部分
echo one &&
echo two &
echo three &&
echo four
这可以重写为
echo one && echo two &
echo three && echo four
首先得到three
and 的原因four
很简单,就是让子 shell 处理one
andtwo
启动并运行比打印three
and需要更长的时间four
。
你可以像这样更清楚地看到这一点
echo one && echo two &
sleep 1
echo three && echo four
在这种情况下,您会得到one
and two
,一秒钟后会得到three
and four
。
请注意,在原始场景中,不能保证one
and不会与andtwo
的输出混合,甚至可以想象,即使插入了单词,例如or 。three
four
thonreee
twfouro
第2部分
echo one &&
(echo two &)
echo three &&
echo four
这可以重写为
echo one && (echo two &)
echo three && echo four
这里发生的是one
立即打印 ,然后two
在子 shell 中触发 。然后(串行)执行下一行,产生three
和four
。在您的特定情况下,子 shell 足够小且速度足够快,可以在输出two
之前打印。three
但也不能保证这一点。
第三部分
括号将语句组合到一个子 shell 中。 & 符号&
适用于语句,但在本例中,您已用于&&
将两个命令链接在一起,因此必须将它们视为单个语句。
也许你应该使用echo one; echo two
而不是echo one && echo two
?他们非常不同。分号;
分隔两个命令,然后这两个命令独立但顺序运行。双 & 符号&&
将两个命令连接在一起逻辑与,这样只有第一个成功完成后,第二个才会运行。比较false; echo yes
、false && echo yes
、 和true && echo yes
。然后通过替换&&
(逻辑与) 和||
(逻辑或)。
奖金
您会丢失作业控制通知,因为子 shell 没有作业控制。