如何执行在Apache重启后仍能继续运行的bash脚本
解决方案
核心思路是让bash脚本完全脱离Apache的进程会话、进程组,不受Apache生命周期影响,以下是经过验证的可行方案:
方案1:使用nohup+后台运行(最简便)
你之前的screen方案无效大概率是没有完成完整的会话脱离操作,nohup的实现方式更简单直接,PHP调用写法如下:
shell_exec('nohup /path/to/your/target.sh > /var/log/script_run.log 2>&1 & echo $!');
关键配置说明:
nohup会让进程忽略SIGHUP信号,避免父进程退出时被连带杀死- 所有输入输出重定向到日志文件(也可以写
/dev/null丢弃输出),避免进程因为IO未处理被挂起 - 末尾的
&让进程直接后台运行,不会阻塞PHP执行 - 可选添加
echo $!返回后台进程PID,方便后续排查问题
方案2:使用systemd临时服务(生产环境更稳定)
如果脚本逻辑复杂、运行时间长,推荐用systemd托管运行,完全和Apache进程解绑:
- 先写通用服务单元模板,保存到
/etc/systemd/system/run-custom-script@.service:
[Unit] Description=Run custom user script %I [Service] Type=oneshot ExecStart=/bin/bash /path/to/your/scripts/%I User=root # 按需替换为脚本运行需要的用户 Group=root
- 重载systemd配置后在PHP中调用触发即可:
shell_exec('systemctl start run-custom-script@your_script_name.sh --no-block');
优势:
- 完全脱离Apache进程树,Apache重启/停止完全不会影响脚本运行
- 自动记录运行日志,可通过
journalctl -u run-custom-script@your_script_name.sh查看执行记录 - 支持配置失败重试、运行超时等扩展规则
方案3:使用at命令调度立即执行
如果系统运行了atd服务,也可以直接把脚本丢给at调度立即执行,自动脱离父进程:
shell_exec('echo "/path/to/your/target.sh" | at now');
注意事项:
- 需要提前安装
at包并确保atd服务处于运行状态 - 适合对启动延迟要求不高的场景
原screen方案修复方式
如果还是需要用screen,要在启动参数中加-d -m强制启动为分离模式,不要附着在当前会话上,写法参考:
shell_exec('screen -d -m -S script_task /path/to/your/target.sh');
之前调用screen无效基本都是没有加-d -m参数,导致screen进程依然和Apache的会话绑定,Apache停止时会被一起杀死。
内容的提问来源于stack exchange,提问作者TurboDaaaan
相关产品推荐
相关产品推荐

