在 bash 中,我观察到 如果我从子外壳开始,调用kill
睡眠进程不会杀死它。你能帮我理解为什么吗?
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
- 使用 subshell 调用
echo $(foo)
,如果我按 enter 来满足read
调用,那么脚本直到结束后才会终止sleep
。 foo
如果我只使用而不是调用该函数$(foo)
,那么脚本会在我按下回车后立即终止。
我真的在这个玩具示例上,但在我的实际工作中,我想将标准输出从foo
一个 shell 变量中捕获,所以我想尽快杀死子 shell。有没有办法让我实现目标的两个部分?
当您使用命令替换
$(foo)
时,shell 需要等待,直到收到命令替换的所有输入。您正在运行的sleep
文件描述符(可能是管道)的副本连接到 shell 读取命令替换输出的位置。(我也很确定它将给出运行循环$!
的 shell 的 PID ,而不是它的内部。)while
sleep
考虑例如这个脚本:
运行它需要 5 秒。
但是将
sleep
行更改为sleep 5 > /dev/null &
,现在脚本立即返回,因为sleep
不再连接到命令替换。请注意,后台睡眠仍将在后台运行,直到超时。你只是不太可能注意到它。请注意,这是特定于命令替换的,而不仅仅是任何子shell 环境。(
(foo)
也将是一个子shell,但应该类似于{ foo; }
, 或只是foo
在这里。)