Bash中如何等待lxterminal窗口关闭以自动重启树莓派常驻应用
核心问题诊断
两版旧脚本失效的根本原因是lxterminal的默认启动机制:启动时会自动将自身fork为后台进程,负责渲染终端窗口,前台的父进程执行完启动参数校验后会立刻退出。
旧脚本的失效逻辑拆解:
- 第一版无后台参数的脚本:lxterminal默认fork到后台,while循环完全不会被终端进程阻塞,会高速空转,短时间弹出上百个终端窗口。
- 第二版增加了
&和wait的脚本:lxterminal派生的后台渲染进程和原父进程完全脱钩,父进程执行完启动动作就立刻退出,通过$!拿到的父进程PID退出后,wait会直接返回,循环仍然会高速运行、不停开新窗口。
该需求完全可实现,以下是按改动量从小到大排序的可行方案:
方案1:最小改动适配现有脚本逻辑
给lxterminal加--no-fork参数,禁止它默认的后台派生行为,让终端进程本身成为可被脚本等待的前台进程,直到窗口关闭才退出。
修改后的脚本:
#!/bin/bash # 捕获退出信号,脚本停止时自动清理终端和应用进程 trap 'pkill -f "mytitle" && pkill -f "myapplication"; exit 0' SIGTERM SIGINT while true do # 加--no-fork参数,脚本会被阻塞直到终端窗口关闭 lxterminal --no-fork --title="mytitle" --geometry=200x200 -e "bash -c './myapplication'" # 代码走到这里说明终端已关闭、应用已退出,延迟1秒重启避免进程频繁拉起 sleep 1 done
方案注意点:
- 用
bash -c包裹应用启动命令,避免应用退出后终端残留空白窗口,应用执行完成后会自动触发终端关闭。 - 因为去掉了后台运行参数,脚本本身会等终端进程完全退出后才进入下一轮循环,不需要额外捕获PID、执行
wait操作。
方案2:直接监控核心应用进程,绕开终端壳的进程逻辑
7*24小时运行的核心目标是保活myapplication本身,不需要纠结外层终端窗口的进程状态。可以把监控目标从lxterminal切换为实际的业务应用,避免终端进程异常导致的保活逻辑失效。
对应的脚本实现:
#!/bin/bash APP_PATH="/home/pi/应用所在路径/myapplication" APP_NAME="myapplication" # 脚本退出时自动清理拉起的应用和终端 trap 'pkill -f "$APP_NAME"; exit 0' SIGTERM SIGINT while true do # 先检查应用是否已在运行,避免重复开窗口 if pgrep -x "$APP_NAME" > /dev/null then sleep 2 continue fi # 启动带终端窗口的应用 lxterminal --title="mytitle" --geometry=200x200 -e "bash -c '$APP_PATH'" & # 等应用进程启动完成,抓到真实的应用PID sleep 1 APP_PID=$(pgrep -x "$APP_NAME") # 循环检测应用是否存活,不管终端窗口状态如何 if [ -n "$APP_PID" ] then while kill -0 "$APP_PID" 2>/dev/null do sleep 1 done fi echo "业务应用已退出,1秒后重新拉起" sleep 1 done
方案优势:
- 不管lxterminal是否因异常崩溃、被误关,只要业务应用还在运行,就不会重复拉起窗口;反过来如果业务应用崩溃,哪怕终端窗口还开着,也会自动重启应用。
- 完全规避lxterminal的fork机制带来的PID捕获失效问题,同时不依赖bash原生的wait子进程检测逻辑,不需要关心进程的父子层级,监控逻辑更贴合实际保活目标。
落地注意事项
- 不要把该脚本放到系统级
rc.local中启动:rc.local是在无图形权限的字符模式下执行的,根本无法拉起带GUI的lxterminal窗口。需要把脚本放到树莓派桌面的自启动目录(~/.config/autostart/对应的启动项),保证图形环境加载完成后再执行保活逻辑。 - 如果发现应用启动后立刻被重复拉起,可以在启动应用前增加0.5-1秒的延迟,避免因为应用启动慢,脚本还没抓到进程PID就进入下一轮判断。
内容的提问来源于stack exchange,提问作者saracoglumert
相关产品推荐
相关产品推荐

