Bash后台进程等待期间执行其他任务的高效实现方案咨询
Bash后台进程等待期间执行其他任务的高效实现方案咨询
嘿,你这个需求太常见啦!确实,用while ((1))这种无限循环轮询不仅占CPU,还真的有概率因为进程异常(比如变成守护进程、PID被复用或者彻底挂死)导致脚本无限跑下去。我给你两个更稳妥高效的方案,解决这些问题:
方案一:用信号监听替代轮询(最推荐)
利用Bash的trap命令监听子进程结束的CHLD信号,这样后台进程一结束,我们就能立刻收到通知,不用一直循环检查PID。这种方式响应及时,还不浪费CPU资源。
修改后的主脚本示例:
#!/bin/bash # 启动后台任务 sleep 10 & pid1=$! # 初始化标记:后台进程还在运行 process_alive=1 # 设置陷阱:当子进程结束时,把标记改成0 trap 'process_alive=0' CHLD # 初始化加载条界面 tput civis # 隐藏光标 echo -e " ----------------------------------" echo -ne "Loading | "; tput sc; # 保存当前光标位置 echo -e " |" echo -e " ----------------------------------" tput rc # 回到保存的光标位置 tput cuu1 # 向上移动一行 tput cuu1 # 循环更新加载条,直到进程结束 while [ $process_alive -eq 1 ]; do # 加载条前进一格 tput cuf 1 echo -n "=" sleep 0.1 # 控制加载速度,避免CPU占用过高 done # 清理陷阱,恢复光标 trap - CHLD tput cnorm echo -e "\nFinished Loading Stuff" exit 0
这个方案的优势:
- 不用主动轮询PID,靠系统信号通知进程状态变化,响应即时
- 加入
sleep 0.1避免空循环占用过多CPU - 从根本上杜绝了无限循环的可能,只要进程结束就会立刻停止循环
方案二:给轮询加超时机制(兜底方案)
如果担心后台进程可能彻底挂死(比如卡死不响应信号),可以给循环加上超时判断,即使进程没结束,到了指定时间也能强制退出循环,避免脚本无限挂着。
加载条脚本可以改成这样:
#!/bin/bash proc_main=$1 tput civis echo -e " ----------------------------------" echo -ne "Loading | "; tput sc; echo -e " |" echo -e " ----------------------------------" tput rc tput cuu1 tput cuu1 # 设置超时时间(比如30秒) timeout_seconds=30 start_timestamp=$(date +%s) # 用kill -0检查进程是否存在(这个命令不会杀掉进程,只是验证PID是否存活) while kill -0 $proc_main 2>/dev/null; do # 更新加载条 tput cuf 1 echo -n "=" sleep 0.1 # 检查是否超时 current_timestamp=$(date +%s) if [ $((current_timestamp - start_timestamp)) -ge $timeout_seconds ]; then echo -e "\nError: 进程超时!已运行超过$timeout_seconds秒" # 可选:杀掉异常进程 kill $proc_main 2>/dev/null break fi done tput cnorm echo -e "\nFinished Loading Stuff" exit 0
这个方案的优势:
- 用
kill -0检查进程状态比单纯判断PID文件更可靠 - 超时机制给脚本加了“安全锁”,即使进程异常也不会无限运行
小提醒
原来的while ((1))空循环之所以不好,除了可能无限跑,还会让CPU一直处于高负载状态,加个短睡眠(比如sleep 0.1)都能大幅降低CPU占用,哪怕用轮询也一定要加哦!
备注:内容来源于stack exchange,提问作者Kaleem Khattak
相关产品推荐
相关产品推荐

