You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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()输出到控制台,完全同步。

注意事项

  1. 确保你的test.sh脚本有执行权限,可以用chmod +x test.sh命令设置。
  2. 因为gulp watch会一直运行,这个Artisan命令也会持续运行,直到你手动按下Ctrl+C终止进程。
  3. 如果你的脚本需要接收输入(比如交互式命令),可以通过标准输入管道($pipes[0])写入内容,但你的场景不需要,所以直接关闭即可。

内容的提问来源于stack exchange,提问作者Norgul

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.07 18:27:58