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

PHP中如何将exec调用的输出(含stderr)重定向至调用程序?及子进程输出未写入日志的问题排查

解决PHP中exec子进程输出(含stderr)重定向到父进程的问题

你的问题核心在于exec函数默认不会将子进程的输出直接传递到父进程的输出流,哪怕你加了2>&1把stderr合并到stdout,这些输出也会被exec直接丢弃,不会自动同步到父进程的输出管道,所以父进程的重定向(> t.log)只能捕获到自身printf的内容。

为什么你的当前代码不生效?

看你这段代码:

exec('/usr/bin/php -f t.php 2 2>&1');

exec函数如果不指定第二个参数(用于捕获输出的数组),它会直接丢弃子进程的stdout内容——哪怕你用2>&1把stderr合并进来,这些内容也不会自动输出到父进程的控制台或重定向目标中,自然不会出现在t.log里。

解决方案1:用proc_open实现输出继承(推荐)

proc_open比exec更灵活,可以让子进程直接继承父进程的stdout和stderr,这样父进程的重定向会自动包含子进程的所有输出,完全不需要硬编码日志文件名。

修改后的代码:

<?php
printf("$argv[1]: ". date("H:i:s")."\n"); 
if ($argv[1] == '1') {
    // 定义子进程的文件描述符,直接复用父进程的标准流
    $descriptorspec = [
        0 => STDIN,   // 子进程使用父进程的输入
        1 => STDOUT,  // 子进程输出直接写入父进程的标准输出
        2 => STDERR   // 子进程错误输出直接写入父进程的标准错误
    ];

    // 启动子进程
    $process = proc_open('/usr/bin/php -f t.php 2', $descriptorspec, $pipes);
    // 等待子进程结束并释放资源
    proc_close($process);
}
?>

执行php -f t.php 1 > t.log后,父进程和子进程的输出都会被写入t.log,完全符合你的预期。

解决方案2:用exec捕获输出后手动打印

如果你坚持使用exec,可以通过捕获输出数组,再手动将内容打印到父进程的输出流,这样重定向就能包含子进程的内容:

<?php
printf("$argv[1]: ". date("H:i:s")."\n"); 
if ($argv[1] == '1') {
    // 捕获子进程的所有输出(含stderr,因为2>&1)
    exec('/usr/bin/php -f t.php 2 2>&1', $outputLines, $returnCode);
    // 逐行打印捕获到的输出,让父进程的重定向能捕获到
    foreach ($outputLines as $line) {
        echo $line . "\n";
    }
}
?>

这个方案同样不需要硬编码日志文件名,完全依赖父进程的命令行重定向完成日志写入。

验证结果

无论使用哪种方案,执行php -f t.php 1 > t.log后,t.log都会包含:

1: 15:10:52
2: 15:10:53

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.04.30 16:52:41