我有最简单的异步执行情况(在后台运行):
#!/bin/bash
# set-eE.sh
set -eE # same as: `set -o errexit -o errtrace`
# global variable
PID=
# handle errors
trap errorfunc ERR
errorfunc(){
echo "error PID=$PID"
}
function func(){
cd nowhere
}
echo "func point"
func &
PID=$!
wait
echo "exit point PID=$PID"
不明白为什么我有下一个输出(注意PID
下的空trap
):
func point
./set-eE.sh: line 16: cd: nowhere: No such file or directory
error PID=
exit point PID=5464
所以,有两个问题:
PID
在 trap errorfunc ERR
下为空答案 0 :(得分:1)
总的来说,进程不是线程。 &
创建一个子进程,该子进程具有创建时的父 shell 执行环境的副本。在子环境中看不到在创建子环境后对父 shell 所做的更改 - 这些是单独的进程。
为什么 ERR 无法访问全局变量
它可以访问自己的全局变量并且它是空的,由PID=
设置。
trap errorfunc ERR下为什么全局变量PID为空
因为它被 PID=
设置为空。
为什么我的脚本不会停止并一直运行到最后?
主 shell 进程不会停止,因为没有命令触发 set -e
在父 shell 中 - 所有命令都以 0 退出状态退出。
我需要脚本在引发 (func &) 任何 ERR 后停止其工作
然后从子shell中杀死父shell。作为一个快速而肮脏的黑客,您可以杀死进程组。
trap 'kill 0' ERR
更好的解决方案是杀死父母
parent=$BASHPID
{
trap 'kill $parent' EXIT
func
} &
您也可以专门等待子wait $PID
,因为子以非零退出状态退出,将返回非零退出状态,这反过来会触发ERR
陷阱父壳。
我需要杀死所有分叉的子shell
然后你必须将上下文转移到父 shell 并在那里进行杀戮。你可以前。将 SIGUSR1 发送到父 shell 并杀死父 shell 中的所有子进程(或者您可以杀死父 shell 并杀死父 shell 的 EXIT 陷阱中的所有子进程)。子进程不知道父进程是否存在其他子进程,因此必须先通知父进程被杀。
见this unix thread。进程与shell环境、进程间通信与进程组研究。