我正在用shell脚本调试一个奇怪的东西,想知道我是否误解了Bash的“fork”(&
)是如何工作的,也许是因为我通常在单个命令中通过终端使用它,例如:< / p>
[~me]$ someExecutable &
现在,在shell脚本中:
foo() {
echo "logic"
}
bar() {
echo "idic"
}
baz() {
echo "katra"
}
foo &
bar
baz
我的目的是异步调用函数foo
,然后让脚本的其余部分继续在原始进程上下文中执行。
当我执行此示例脚本时,我做获得预期的输出:
logic
idic
katra
(也就是说,只对bar
和baz
发出一次明显的调用;我完全不会被三行的相对顺序所困扰输出,我理解可能会有所不同)
但我可能误解了输出和脚本本身。如果是这样,那肯定会解释我在实际代码中看到的奇怪之处,并且让我不必再深入挖掘。
在子进程中,在调用foo
之后,forked shell脚本是否可能会继续?这意味着我的shell脚本的其余部分将被执行两次?
在Bash脚本中使用&
时会发生什么?
答案 0 :(得分:3)
&符号仅在您的示例中分配对foo()的调用。它不是分支整个脚本。只有foo()在一个单独的线程中运行,当foo()结束时它会退出。 bar()和baz()继续在同一个线程中运行
答案 1 :(得分:2)
bash中的&
不是分叉。
它告诉bash在子shell中启动命令,并继续解析其他命令(而不是等待该命令完成)。
因此,正如您所料,它在后台运行'foo',并继续处理顶级shell中的'bar'和'baz'命令。没有发生调用shell的分叉,但是'foo'在后台运行。
所以“foo”的输出实际上可能发生在bar或baz之后,具体取决于它的内容..但是因为它使用“echo”,这是一个内置的shell,当“foo”后台进程设置时, “echo”可立即使用:因此,在调用shell传递给下一个命令之前,你很有可能看到它的输出,这显然是你的情况。 (但是YMMV!如果“foo”正在调用一个沉重的外部命令,它的输出可能会在稍后发生)
在终端中,它几乎是一样的:你可以考虑一个带有shell提示符的终端窗口作为该shell的文件脚本,登录shell正在“按你键入时”读取。行为几乎相同。
答案 2 :(得分:1)
&
字符告诉shell在后台执行命令(或一组命令)。
立即执行下一个命令。
没有两次执行脚本的危险,因此在这方面它与C fork()
不同。
答案 3 :(得分:1)
除了控制操作符&
导致命令在子shell 1 中异步执行之外,您可以使用Coprocesses来实现控制输出。
而不是通过说:
来调用该函数foo &
说:
coproc fubar { foo; }
然后通过说:
读取输出cat <&"${fubar[0]}"
这也允许您控制输出(是否需要在bar
或baz
等其他函数之前或之后发出。
例如,以下内容:
foo() {
echo "logic1"
echo "logic2"
}
bar() {
echo "idic"
}
baz() {
echo "katra"
}
coproc fubar { foo; }
bar
baz
cat <&"${fubar[0]}"
会产生:
idic
katra
logic1
logic2
答案 4 :(得分:0)
实际上这个命令确实运行你的函数foo后台:
foo &
但是当你输入bar
和baz
时,foo已经完成了它的运行并在你的终端上打印了它的输出。
但是,如果您运行这样的功能,那么您会注意到差异:
foo & bar; baz
[1] 46453
idic
katra
logic
[1]+ Done foo
此处您的流程ID可能与我的不同,但您可以看到logic
在其他2个功能的输出后最终打印出来。