![循环忽略后台子 shell 中变量的更改](https://linux22.com/image/71669/%E5%BE%AA%E7%8E%AF%E5%BF%BD%E7%95%A5%E5%90%8E%E5%8F%B0%E5%AD%90%20shell%20%E4%B8%AD%E5%8F%98%E9%87%8F%E7%9A%84%E6%9B%B4%E6%94%B9.png)
我编写了一个包含循环的脚本until
。该循环应该一直运行,直到true
从循环外部将布尔变量设置为为止。不幸的是,循环忽略了变量已设置为 true 并继续运行。以下是产生此问题的几行:
boolean=false
{ sleep 5 && boolean=true && echo "boolean is true now" ; } &
{ until [ "$boolean" = true ] ; do sleep 1 && echo $boolean ; done ; } &&
echo "boolean is true now: $boolean"
生成的输出是:
false
false
false
false
boolean is true now
false
false
false
...
boolean
当设置为时,如何使循环退出true
?
答案1
可以使用信号在前台 shell 和后台 shell 之间进行通信:
#!/bin/bash
# global variable for foreground shell
boolean=false
# register a signal handler for SIGUSR1
trap handler USR1
# the handler sets the global variable
handler() { boolean=true; }
echo "before: $boolean"
# Here, "$$" is the pid of the foreground shell
{ sleep 5; kill -USR1 $$; echo "finished background process"; } &
# busy waiting
until $boolean; do
echo "waiting..."
sleep 1
done
echo "after: $boolean"
输出
before: false
waiting...
waiting...
waiting...
waiting...
waiting...
finished background process
after: true
答案2
角色&
进行后台进程。后台进程在子 shell 中异步执行。变量可以从父 shell 传递到子 shell,而不是相反。但是,如果您确实需要子 shell 中设置的值,则可以采取解决方法:
boolean=$(mktemp) && echo "false" >$boolean
{ sleep 5 && echo true >$boolean && echo "boolean is true now" ; } &
{ until [ "$(cat $boolean)" = "true" ] ; do sleep 1 && cat $boolean ; done ; } &&
echo "boolean is true now: $(cat $boolean)"
这会生成一个临时文件,其内容是布尔值。在until
循环中检查该文件直到它包含 true。
注意:
我建议在您的脚本中执行以下操作(如果可能):
{ sleep 5 && echo "background process done" ; } &
wait
echo "continue in foregound."
wait
等待后台进程完成。
答案3
您错误地认为boolean
在第二行中设置为 true 的布尔值与您在until
语句中测试的布尔值相同。情况并非如此,您启动新进程,在后台使用一个新的 shell,并且boolean
(您测试的那个)永远不会被分配。