在 bash 中,我观察到调用kill
睡眠进程惯于 如果我从子 shell 开始,就杀死它。你能帮我理解为什么吗?
function foo () {
# Start a loop with `sleep` in the background
while true; do
>&2 echo looping
sleep 5
done &
# Wait for user input, then kill the "sleep" loop
loop_id=$!
read -p 'press enter' DUMMY
kill $loop_id
}
echo $(foo) # Call foo within a subshell
echo "DONE"
可能会发生两种截然不同的情况,具体取决于最后一行是否使用子 shell
- 使用子 shell 调用
echo $(foo)
,如果我按 Enter 来满足read
调用,那么脚本直到sleep
结束后才会终止。 - 如果我使用 just
foo
而不是调用该函数$(foo)
,那么一旦我按 Enter 键,脚本就会终止。
我确实在这个玩具示例中,但在我的实际工作中,我想将标准输出捕获foo
到 shell 变量中,所以我想尽快杀死子 shell。有没有办法让我同时实现这两个目标?
答案1
当您使用命令替换时$(foo)
,shell 需要等待,直到收到命令替换的所有输入。您sleep
正在运行的文件描述符(可能是管道)的副本连接到 shell 读取命令替换输出的位置。 (我也很确定它将$!
给出运行循环的 shell 的 PID while
,而不是sleep
其内部的 PID。)
考虑例如这个脚本:
foo() {
sleep 5 &
echo foo
}
tmp=$(foo)
echo end.
运行需要5秒。
但是将该行更改sleep
为sleep 5 > /dev/null &
,现在脚本立即返回,因为sleep
不再连接到命令替换。请注意,后台睡眠仍将在后台运行,直到超时。你只是不太可能注意到它。
请注意,这是特定于命令替换,不仅仅是任何子 shell 环境。 ((foo)
也可以是一个子 shell,但应该与{ foo; }
, 或仅foo
在此处工作。)