正确做法是用 while true 包裹主逻辑并配合 trap 捕获信号,通过 timeout + pidof + 健康探针检测崩溃,采用指数退避重启策略、限制最大重试次数,同时维护 pidfile 和日志重定向以保障可观测性。

用 Shell 写一个“类守护进程”的死循环监控脚本,核心不是真的变成系统级 daemon(那需要 fork + setsid + 重定向等),而是实现持续运行、自动检测异常、崩溃后立即重启这三点。关键在于避免无限阻塞、合理捕获退出、控制重启节奏,并防止雪崩式拉起。
用 while true + trap 实现可靠死循环
别直接写 while true; do ./myapp; done —— 这样一旦 myapp 崩溃或被 kill,整个脚本就退出了,达不到“自愈”效果。正确做法是:
- 用
while true包裹主逻辑,确保外层永不退出 - 用
trap捕获 SIGTERM/SIGINT,做优雅清理(比如删 pidfile、发通知) - 每次启动子程序前检查是否已在运行(避免重复拉起),可用
pidof或锁文件
崩溃检测不能只靠 exit code,要加超时和健康检查
有些程序崩溃不一定会返回非零退出码(比如卡死、假死、内存泄漏),所以单靠 $? 不够。建议组合使用:
Shell本身是一个用C语言编写的程序,它是用户使用Linux的桥梁。Shell既是一种命令语言,又是一种程序设计语言。作为命令语言,它交互式地解释和执行用户输入的命令;作为程序设计语言,它定义了各种变量和参数,并提供了许多在高级语言中才具有的控制结构,包括循环和分支。它虽然不是Linux系统核心的一部分,但它调用了系统核心的大部分功能来执行程序、建立文件并以并行的方式协调各个程序的运行。因此,对于用户来说,shell是最重要的实用程序,深入了解和熟练掌握shell的特性极其使用方法,是用好Linux系统
-
超时兜底:用
timeout 30s ./myapp,强制 30 秒没响应就杀掉并重启 -
进程存活检查:启动后 sleep 2s,再用
pidof myapp或pgrep -f "myapp"确认还在跑 -
简单健康探针(可选):如果 myapp 提供 HTTP 接口或状态文件,加一行
curl -sf http://127.0.0.1:8080/health || exit 1
重启前加退避(backoff)和最大尝试次数
连续快速重启容易掩盖问题,还可能打满 CPU 或触发系统限制。加入可控的重启策略:
- 首次失败后等待 1 秒,第二次 2 秒,第三次 4 秒……按指数退避(
sleep $((2**attempts))) - 设置最大重试次数(如 10 次),超限后写日志、发告警、然后
exit 1停止自愈 - 把当前尝试次数、上次退出码、时间戳记到日志里,方便排查是偶发还是必现
加上 pidfile 和日志重定向,便于运维管理
虽然不是 systemd service,但要有基本可观测性:
- 启动时写
/var/run/myapp-monitor.pid,退出时清理;别人想 stop 就能kill $(cat /var/run/myapp-monitor.pid) - 所有输出重定向到日志文件:
> /var/log/myapp-monitor.log 2>&1,避免 stdout/stderr 丢失 - 用
logger -t myapp-monitor把关键事件(启动、重启、失败)也推到 syslog,方便集中收集










