Laravel Artisan执行持续脚本如何实现控制台实时输出?
解决Laravel Artisan命令实时输出长期运行脚本的问题
嗨,我太懂你的困扰了——exec()函数确实天生不适合处理这种不会终止的进程,它得等整个脚本完全跑完才会把所有输出一次性返回,所以你根本看不到那两条echo的内容,更别说gulp watch的实时更新了。
要实现实时输出,你得换成PHP的proc_open()函数,它能让你直接和子进程的输入输出流交互,实时捕获每一行输出。下面是具体的实现方案:
替换exec为proc_open的代码示例
把你原来的exec代码替换成这段,放在你的Artisan命令类里:
// 定义进程的输入输出描述符 $descriptorspec = [ 0 => ["pipe", "r"], // 标准输入(我们不需要给脚本传内容,后面会关闭) 1 => ["pipe", "w"], // 标准输出(用来捕获脚本的正常输出) 2 => ["pipe", "w"] // 标准错误(用来捕获错误信息,可选) ]; // 启动子进程执行test.sh $process = proc_open($basedir . "test.sh", $descriptorspec, $pipes); // 检查进程是否成功启动 if (is_resource($process)) { // 关闭标准输入管道,因为我们不需要向脚本输入任何内容 fclose($pipes[0]); // 实时读取标准输出,每读到一行就立刻输出到控制台 while (!feof($pipes[1])) { $line = fgets($pipes[1]); if ($line !== false) { // 用Artisan的info方法输出,保持命令行风格一致 $this->info(trim($line)); } } // 可选:实时读取标准错误输出,用error方法标记错误内容 while (!feof($pipes[2])) { $line = fgets($pipes[2]); if ($line !== false) { $this->error(trim($line)); } } // 关闭所有管道并回收进程资源 fclose($pipes[1]); fclose($pipes[2]); proc_close($process); }
为什么这个方法有效?
proc_open()和exec()最大的区别在于,它不会死等子进程结束,而是创建了三个管道让你和子进程实时通信。脚本里的每一行输出(包括那两条echo和gulp watch的实时日志)都会通过标准输出管道立刻被读取,然后用$this->info()输出到控制台,完全同步。
注意事项
- 确保你的
test.sh脚本有执行权限,可以用chmod +x test.sh命令设置。 - 因为gulp watch会一直运行,这个Artisan命令也会持续运行,直到你手动按下
Ctrl+C终止进程。 - 如果你的脚本需要接收输入(比如交互式命令),可以通过标准输入管道($pipes[0])写入内容,但你的场景不需要,所以直接关闭即可。
内容的提问来源于stack exchange,提问作者Norgul
相关产品推荐
相关产品推荐

