嵌套函数并发出错时Shell脚本未退出的解决需求(bash4.2无wait-n)
问题:并发子进程出错时Shell脚本未终止
你的Shell脚本在多个嵌套函数并发执行出错时,不会终止仍继续运行。示例代码如下:
status() { exit_st=$1 error_1=$2 if ! [[ $exit_st -eq 0 ]]; then echo "[ERROR] - ${error_1}" exit 1 else echo "[INFO] - ${error_1}" fi } abc(){ val1= $1 val2= $2 #Some SQL command here status $? "SQL command step" } abc cmd1 cmd2 & abc cmd3 cmd4 & wait echo 'hi'
当#Some SQL command here处的命令执行失败时,脚本并未退出,反而继续执行并打印hi。将status函数中的exit改为return也无法实现脚本出错退出的效果。需求是:只要任意abc子进程执行失败,整个脚本就以非零状态码退出。注意使用的是GNU bash, version 4.2.46(2)-release (x86_64-redhat-linux-gnu)版本,无法使用wait -n选项。
原因分析
- 子进程中执行
exit 1只会终止当前子进程,不会影响父脚本的运行,父脚本仍会等待所有子进程完成后继续执行。 - 改为
return只是让abc函数返回非零值,但子进程本身的退出状态会保留这个值,可父脚本的wait默认只会等待所有子进程结束,不会因为某个子进程失败而主动终止。 - 原脚本中
val1= $1和val2= $2存在语法错误,变量赋值时等号前后不能有空格,会导致执行报错。
解决方案
通过记录每个子进程的PID,逐个等待并检查退出状态,一旦发现非零状态码,立即终止脚本并杀死剩余未完成的子进程。修改后的脚本如下:
# 存储子进程PID的数组 declare -a pids status() { exit_st=$1 error_1=$2 if ! [[ $exit_st -eq 0 ]]; then echo "[ERROR] - ${error_1}" exit 1 else echo "[INFO] - ${error_1}" fi } abc(){ val1="$1" val2="$2" # 替换为实际SQL命令,此处用false模拟执行失败 false status $? "SQL command step for $val1 $val2" } # 启动子进程并记录PID abc cmd1 cmd2 & pids+=($!) abc cmd3 cmd4 & pids+=($!) # 遍历PID数组,逐个检查子进程状态 for pid in "${pids[@]}"; do wait "$pid" exit_code=$? if [[ $exit_code -ne 0 ]]; then echo "[FATAL] - 子进程PID $pid 执行失败,终止脚本" # 杀死剩余运行中的子进程 for remaining_pid in "${pids[@]}"; do if kill -0 "$remaining_pid" 2>/dev/null; then kill "$remaining_pid" echo "[INFO] - 已终止子进程PID $remaining_pid" fi done exit "$exit_code" fi done # 所有子进程成功才执行后续代码 echo 'hi'
关键说明
- 用数组
pids存储每个后台子进程的PID($!表示最后一个后台进程的PID)。 - 逐个
wait每个PID,检查其退出状态:- 若某个子进程退出状态非零,立即打印错误信息。
- 用
kill -0检查剩余PID对应的进程是否还在运行,若存在则杀死,避免无效执行。 - 最后以该子进程的退出状态码终止整个脚本。
- 修复了变量赋值的语法错误,确保参数正常传递。
内容的提问来源于stack exchange,提问作者dijeah
相关产品推荐
相关产品推荐

