我一直在与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()
的{{1}},但是在网页上下文中运行后会输出NULL
:
hi
这也输出了东西:
echo exec("echo 'hi'");
但是,只要我使用echo exec("atq");
,就不会输出任何内容。如何获得输出:
at
因为目前PHP通过Apache以“正常”运行时没有输出任何内容,但是在终端以及PHP的交互式控制台中运行命令会给我预期的结果:
exec("echo 'php -f /path/to/file.php foo=1' | at now + 1 minutes", $result);
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
给了我输出。我搜索并阅读了this question,但都无济于事。
如果exec()
使用第二个参数exec()
,我如何让at
将exec()
的输出返回到字符串或数组?
答案 0 :(得分:27)
我没有意识到这可能是这么简单。所需要的只是通过将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,{{1} }不读!我要感谢@Tourniquet指出这一点,但是他已经删除了他的答案。引用:
据我所见,在输出到stderr时,未被捕获 EXEC。我对此并不是很有信心,但考虑使用 http://php.net/manual/en/function.proc-open.php,允许你这样做 直接stderr到自己的管道。
这实际上是正确的做事方式。我的解决方案(因为我只想要stderr)是这样做的:
exec()
// 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);
}
现在包含打印到stderr的任何$output
(这应该是stdout,因为它不是错误),at
成功时包含$return_value
。
答案 1 :(得分: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);
我希望这有助于: - )
答案 2 :(得分:0)
尝试创建最小(非)工作示例。打破一切,一次只测试一件事。
以下是您的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
的输出是通过邮件发送给我的!