cron执行日志检测重启脚本失败问题求助及简化方案咨询
问题解决与优化方案
原问题核心错误点
- Cron的
timeout 5s设置完全错误:你的脚本用tail -fn0是持续实时监听日志,而timeout 5s会在5秒后强制杀死脚本,导致脚本根本来不及检测日志内容。 - 脚本运行模式与Cron不匹配:持续监听的脚本适合后台常驻,而非Cron每分钟调用一次——每次调用都会重新启动监听,且存活时间极短,完全起不到监控作用。
- 潜在的环境变量问题:Cron默认PATH不包含
/sbin等系统目录,虽你脚本里写了/sbin/reboot的绝对路径,但仍建议在脚本内明确设置PATH避免其他命令报错。
修复方案一:常驻后台的实时监控脚本(推荐)
这种方式让脚本一直运行,实时跟踪日志,效率最高且响应及时:
修改后的脚本 /home/root/resetiferror.sh
#!/bin/bash # 明确设置环境变量PATH,避免命令找不到 export PATH=/usr/bin:/bin:/sbin:/usr/sbin # 定义日志路径 TARGET_LOG="/var/log/messages" MONITOR_RECORD="/var/log/resetiferror" # 实时跟踪日志,逐行检查 tail -fn0 "$TARGET_LOG" | while read -r line; do # 匹配关键词(忽略大小写) if echo "$line" | grep -qi "failed to read"; then echo "$(date '+%Y-%m-%d %H:%M:%S') 检测到异常,执行系统重启" >> "$MONITOR_RECORD" # 执行重启(用绝对路径确保可靠) /sbin/reboot fi done
部署方式
- 确保脚本可执行:
chmod +x /home/root/resetiferror.sh - 后台启动并设置开机自启:
- 临时启动:
nohup /home/root/resetiferror.sh > /dev/null 2>&1 & - 永久开机自启(Systemd系统):
创建服务文件/etc/systemd/system/resetiferror.service:
启用服务:[Unit] Description=监控/var/log/messages异常并触发重启 After=syslog.target [Service] Type=simple ExecStart=/home/root/resetiferror.sh Restart=always User=root [Install] WantedBy=multi-user.targetsystemctl daemon-reload systemctl enable --now resetiferror.service
- 临时启动:
修复方案二:Cron周期性检查日志(适合非实时场景)
如果不需要实时响应,可让Cron每分钟检查一次新增的日志内容,避免重复触发:
优化后的脚本 /home/root/resetiferror.sh
#!/bin/bash export PATH=/usr/bin:/bin:/sbin:/usr/sbin TARGET_LOG="/var/log/messages" MONITOR_RECORD="/var/log/resetiferror" # 记录上次检查的日志位置,避免重复检测 POS_FILE="/var/log/resetiferror.pos" # 初始化位置文件(首次运行时) if [ ! -f "$POS_FILE" ]; then echo "$(stat -c %s "$TARGET_LOG")" > "$POS_FILE" fi CURRENT_SIZE=$(stat -c %s "$TARGET_LOG") LAST_SIZE=$(cat "$POS_FILE") # 处理日志轮转(日志文件变小的情况) if [ "$CURRENT_SIZE" -lt "$LAST_SIZE" ]; then LAST_SIZE=0 fi # 检查上次检查后新增的日志内容 tail -c +$((LAST_SIZE + 1)) "$TARGET_LOG" | grep -qi "failed to read" if [ $? -eq 0 ]; then echo "$(date '+%Y-%m-%d %H:%M:%S') 检测到异常,执行系统重启" >> "$MONITOR_RECORD" /sbin/reboot fi # 更新检查位置 echo "$CURRENT_SIZE" > "$POS_FILE"
Cron配置
替换原Cron任务,去掉timeout,设置每分钟运行:
* * * * * /home/root/resetiferror.sh >> /var/log/resetiferror.log 2>&1
更简便的替代思路
如果系统支持journalctl(Systemd系统),可直接用它跟踪日志,无需脚本:
journalctl -fu systemd-journald | grep -qi "failed to read" && /sbin/reboot
将此命令加入开机自启即可,逻辑和脚本一致,但更简洁。
内容的提问来源于stack exchange,提问作者twsnnl
相关产品推荐
相关产品推荐

