17

当我使用Unix 系统命令添加任务时,我一直在exec()努力,试图从中捕获输出。at我的问题是从我的脚本运行时它没有输出,但是从终端运行它并且PHP 以交互模式打印出几行。

我要执行的命令是这样的:

echo exec("echo 'php -f /path/to/file.php foo=1' | at now + 1 minutes", $result);

var_dump()string(0) "",print_r()吐 出来Array (). 我尝试过使用shell_exec(), 其中输出,但是在网页上下文中运行时会出现NULL以下输出:hi

echo exec("echo 'hi'");

这也输出了东西:

echo exec("atq");

但是,一旦我使用at,什么都不会输出。如何获得以下输出:

exec("echo 'php -f /path/to/file.php foo=1' | at now + 1 minutes", $result);

因为目前它在 PHP 通过 Apache 以“正常”方式运行时不输出任何内容,但是在终端以及 PHP 的交互式控制台中运行该命令给了我类似的预期结果:

php > echo exec("echo 'php -f /path/to/file.php foo=1' | at now + 1 minutes", $result);
warning: commands will be executed using /bin/sh
job 1219 at Sun Jun 10 12:43:00 2012

safe_mode已关闭,并且我无法弄清楚为什么at在执行atq或任何其他推荐exec()给我输出时使用管道输入的 echo 语句没有得到任何输出。我已经搜索并阅读了这个问题,但无济于事。

如果使用带有的第二个参数,我如何才能exec()将输出返回at到字符串或数组exec()

4

3 回答 3

29

工作,一条线解决方案

我没想到会这么简单。所需要做的就是通过将2>&1要执行的命令放在末尾来将 stderr 重新路由到 stdout。现在任何输出at都打印到标准输出,因此被捕获exec()

echo exec("echo 'php -f /path/to/file.php foo=1' | at now + 1 minutes 2>&1", $result);

我的旧解决方案:

我试图保持一个/两行解决方案,但是最终唯一有效的方法是使用proc_open() 因为at日志到 stderr,它exec()不会读取!我要感谢@Tourniquet 指出这一点,但他已经删除了他的答案。去引用:

据我所知,在输出到 stderr 时,exec 没有捕获到。我对此不是很自信,但考虑使用 http://php.net/manual/en/function.proc-open.php,它允许您将 stderr 引导到它自己的管道。

这实际上是正确的做事方式。我的解决方案(因为我只想要标准错误)是这样做的:

// Open process to run `at` command
$process = proc_open("echo 'php -f /path/to/file.php foo=1' | at now + 1 minutes", array(2 => array("pipe", "w")), $pipes);

// Get stuff from stderr, because `at` prints out there for some odd reason
if(is_resource($process)) {
    $output = stream_get_contents($pipes[2], 100);
    fclose($pipes[2]);

    $return_value = proc_close($process);
}

$output现在包含at打印到 stderr 的任何内容(应该真正进入 stdout,因为它不是错误),并且$return_value包含0成功。

于 2012-06-10T13:43:11.080 回答
8

这里有一个更复杂的proc_open解决方案。我正在写这个答案,因为在我的情况下,'2>&1'解决方法不起作用。

function runCommand($bin, $command = '', $force = true)
{
    $stream = null;
    $bin .= $force ? ' 2>&1' : '';

    $descriptorSpec = array
    (
        0 => array('pipe', 'r'),
        1 => array('pipe', 'w')
    );

    $process = proc_open($bin, $descriptorSpec, $pipes);

    if (is_resource($process))
    {
        fwrite($pipes[0], $command);
        fclose($pipes[0]);

        $stream = stream_get_contents($pipes[1]);
        fclose($pipes[1]);

        proc_close($process);
    }

    return $stream;
}

使用示例:

// getting the mime type of a supplied file
echo runCommand('file -bi ' . escapeshellarg($file));

使用命令参数的另一个示例:

// executing php code on the fly
echo runCommand('/usr/bin/php', '<?php echo "hello world!"; ?>');

另一个使用force参数的示例(这对于将在执行过程中更改输出的命令很有用):

// converting an mp3 to a wav file
echo runCommand('lame --decode ' . escapeshellarg($source) . ' ' . escapeshellarg($dest), '', true);

我希望这会有所帮助:-)

于 2013-06-07T13:43:27.553 回答
1

尝试创建一个最小(非)工作示例。分解一切,一次只测试一件事。

这是您的 bash 中的一个错误:

hpek@melda:~/temp$ echo 'php -f /path/to/file.php foo=1' | at now + 1 minutes
at: pluralization is wrong
job 22 at Sun Jun 10 14:48:00 2012
hpek@melda:~/temp$ 

minute改为og minutes

我的输出at是通过邮件发送给我的!

于 2012-06-10T12:50:06.927 回答