我一直在与exec()
搏斗,当我使用 at
Unix 系统命令添加任务时,试图从中捕获输出。我的问题是,从我的脚本运行时它没有给出任何输出,但是从终端运行它,在交互模式下的 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
关闭了,我无法弄清楚为什么在atq
执行带有管道输入 echo 语句的at
中获得任何输出时,exec()
给我输出。我已经搜索并阅读了这个问题,但都无济于事。
如果使用带有 exec()
的第二个参数,我如何让exec()
将输出从 at
返回到字符串或数组?
工作,单行解决方案
我没有意识到它可以这么简单。所需要的只是通过将 2>&1
stderr 放在要执行的命令末尾来将 stderr 重新路由到 stdout。现在,at
的任何输出都打印到 stdout,因此由 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,这没有被捕获 执行官。我对此不太有信心,但请考虑使用 http://php.net/manual/en/function.proc-open.php,它允许您 将 STDERR 定向到自己的管道。
这其实才是正确的做事方式。我的解决方案(因为我只想要 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
现在包含打印到 stderr 的任何at
(它应该真正转到 stdout,因为它不是错误),$return_value
包含成功0
。
这里有一个更复杂的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);
我希望这有帮助:-)
尝试创建一个最小(非)工作示例。分解一切,一次只测试一件事。
这是你的抨击中的一个错误:
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
输出通过邮件发送给我!!