里面man bash
说:
等待 [-fn] [id ...]
等待每个指定的子进程并返回其终止状态。每个 id 可能是一个进程 ID 或一个作业规范;如果给出了作业规范,则等待该作业管道中的所有进程。如果没有给出id,则等待所有当前活动的子进程,返回状态为零。如果提供了 -n 选项,wait 将等待任何作业终止并返回其退出状态。
和典型的例子,如
command1 & command2 & command3 & wait
将意味着三个命令并行运行,并且只有在所有命令都完成后才能完成下一步。
我的问题在于这两个 bash 脚本的结果:
#!/bin/bash
for i in 1 2 3 ; do
a=$i
echo "$a is $i"
done 2>/dev/null
结果:
1 is 1
2 is 2
3 is 3
和我预期的差不多。现在我假设分配变量是一个漫长的过程,所以我等待它:
#!/bin/bash
for i in 1 2 3 ; do
a=$i & wait
echo "$a is $i"
done 2>/dev/null
结果是:
3 is 1
3 is 2
3 is 3
我很困惑,原因如下:
- 唯一
wait
应该等待完成的过程是分配变量,然后应该运行脚本中的下一步(echo
)。a=3
应该只发生在循环的最后一次迭代中。 - 据我所知,
for
-loops 在子shell 中运行,并且wait
仅适用于启动它的shell。因此它甚至不应该等待for
-loop 完成(因为这是父shell)。 - 我从来没有指定与
echo
其他进程并行运行,所以我没想到会出现竞速情况。
那么为什么当变量不是a
时,-variable 设置与最后一次循环迭代呢?我误解$i
了命令的哪一部分?wait
这种行为完全出乎我的意料。
GNU bash,版本 5.0.3(1),基于 5.7.0-0.bpo.2-amd64 Linux 内核。
预先取消设置a
使第二个脚本返回这个
is 1
is 2
is 3
即该变量从未设置过,并且是从我之前的运行中拖出来的。
for
循环不在子shell 中运行,例如,您可以拥有for i in 1 2 3; do a=foo; done; echo $a
并且它会打印foo
,即使该变量在循环外使用。循环变量的值也是循环最后分配给它的任何值(如果循环被break
退出,它可能不是最后一个值)。但是 using
&
确实将该命令放在子shell中,并且a=$i &
do 只在子shell中进行分配。您当然也可以在子外壳中使用分配的值:例如:
会打印
做一些类似
{ a=$i; echo "$a"; } &
验证的事情。让后台命令访问(和修改!)主 shell 中的变量将需要进程之间的一些同步,这会给 shell 带来复杂性,但收益可能相对较小。
如果你确实需要它,例如,如果你有一个长时间运行的命令,你想在后台运行,但需要输出,你必须做一些事情,比如将输出临时存储在一个文件中,例如
或者使用专门为并行运行命令而构建的 GNU Parallel 之类的东西。它还具有
parset
应该能够为 shell 变量赋值的命令。至于为什么你
3
从$a
循环的每次迭代中得到,那可能是因为你之前运行了第一个循环,它离开a
了3
. 将所有后续分配推到子a
外壳中,这就是整个循环中主外壳保留的值。