PHP中如何后台运行含延时的多条Bash命令?
解决PHP中后台运行带延时的多条Bash命令问题
这个问题我之前做流媒体推送时也踩过坑——用子shell(sleep 5; ...) &的写法在终端里没问题,但在PHP的exec()里就会导致脚本阻塞等待。核心原因是PHP的exec()没有完全和子shell进程脱离关联,下面给你几个经过验证的可行方案:
方案一:用nohup + bash -c彻底脱离终端
给命令套上nohup和bash -c,让进程完全脱离当前PHP会话的终端关联,这样PHP就不会一直等命令执行完:
$cmd = 'nohup bash -c "sleep 5; ffmpeg -re -i ./97.mp4 -vcodec copy -acodec copy -f flv -y rtmp://example.com/c/190843?auth_key=7e2682b5 > output 2>&1 </dev/null" &'; exec($cmd, $output, $return_var);
bash -c:把多条命令打包成一个字符串交给bash执行,避免子shell的关联问题nohup:让进程忽略挂起信号,即使PHP进程结束,后台的sleep和ffmpeg也能继续运行
方案二:用proc_open()替代exec()(更灵活可控)
exec()的封装性太强,proc_open()可以直接控制进程的输入输出流,主动切断PHP与后台进程的关联:
// 定义输入输出流的指向 $descriptorspec = [ 0 => ['file', '/dev/null', 'r'], // 标准输入重定向到/dev/null 1 => ['file', 'output', 'w'], // 标准输出写入output文件 2 => ['file', 'output', 'w'] // 标准错误也写入output文件 ]; // 要执行的命令串 $cmd = 'sleep 5; ffmpeg -re -i ./97.mp4 -vcodec copy -acodec copy -f flv -y rtmp://example.com/c/190843?auth_key=7e2682b5'; // 启动进程 $process = proc_open($cmd, $descriptorspec, $pipes); // 立即关闭所有管道并释放进程资源,不让PHP阻塞等待 if (is_resource($process)) { foreach ($pipes as $pipe) { fclose($pipe); } proc_close($process); }
这个方案适合需要对进程做更精细控制的场景,比如实时获取输出或者调整参数。
方案三:写入临时Bash脚本再后台执行
如果命令串比较复杂,或者担心转义问题,可以把命令写成独立的bash脚本,再后台执行:
// 编写临时脚本内容 $scriptContent = '#!/bin/bash sleep 5 ffmpeg -re -i ./97.mp4 -vcodec copy -acodec copy -f flv -y rtmp://example.com/c/190843?auth_key=7e2682b5 > output 2>&1 </dev/null # 可选:脚本执行完后自动删除自己 rm "$0" '; // 创建临时脚本文件 $tmpScript = tempnam(sys_get_temp_dir(), 'delayed_ffmpeg'); file_put_contents($tmpScript, $scriptContent); chmod($tmpScript, 0755); // 添加执行权限 // 后台运行脚本 $cmd = "$tmpScript &"; exec($cmd, $output, $return_var);
这种方式最稳妥,完全避免了PHP与命令进程的关联问题,而且脚本可以复用或修改。
额外注意事项
- 确保PHP运行用户(比如www-data)有执行
ffmpeg、读写output文件、访问临时目录的权限 - 测试时可以先把ffmpeg换成
echo "test",验证sleep延时和后台运行是否正常,再替换回真实命令 - 如果需要记录日志,确保
output文件的路径是PHP可写的
内容的提问来源于stack exchange,提问作者LF-DevJourney
相关产品推荐
相关产品推荐

