在PHP中抑制exec()调用的输出

30
我有一些使用PHP的命令行脚本,使用exec()来执行一些任务,比如重新启动服务、加载MySQL时区文件等等。虽然exec()本身不会在屏幕上输出任何内容,但是我运行的一些命令会强制输出一些我无法抑制的内容(即使使用ob_start()/ob_end_clean()也无效)。例如,以下命令会将时区文件加载到MySQL中。我们定期运行此命令以确保MySQL的时区数据是最新的。
 $command = 'mysql_tzinfo_to_sql /usr/share/zoneinfo | mysql mysql';
 exec($command, $output, $result);

在这个例子中,我希望所有命令的输出都被写入$output,但我仍然会看到以下输出被强制显示在屏幕上。
Warning: Unable to load '/usr/share/zoneinfo/Asia/Riyadh87' as time zone. Skipping it.
Warning: Unable to load '/usr/share/zoneinfo/Asia/Riyadh88' as time zone. Skipping it.
Warning: Unable to load '/usr/share/zoneinfo/Asia/Riyadh89' as time zone. Skipping it.
...

有没有办法抑制这个输出?重定向到/dev/null并不理想,因为这会导致PHP继续处理而不等待命令完成。
提前感谢, ~ JamesArmes

3
对于那些想知道为什么示例代码无法正常工作的人,原因在于只有 stdout 被捕获了,而给出的错误信息被写入到 stderr 中,并没有被捕获,而是直接显示在屏幕上。 - etheros
1
我通过谷歌搜索进入了这个帖子,寻找在运行 PHP CLI 脚本时抑制所有输出的方法。我的解决方案是将 exec() 调用包装在 ob_start()ob_end_clean() 中。 - Alex S
4个回答

28

仅重定向stderr不应影响处理发生的位置,只需确保不要添加&即可。仅在您重定向输出并使其在后台运行时,它才应该在后台运行。

编辑:

查看cygwin,您需要为第一个命令重定向stderr,请尝试使用以下命令:

$command = 'mysql_tzinfo_to_sql /usr/share/zoneinfo 2> /dev/null | mysql mysql';
exec($command, $output, $result);

这并不完全正确。PHP手册的意思是,如果你仅使用“&”,而没有重定向,PHP仍然会挂起。仅有的重定向也不能使其在后台运行。 - Ben James
嗯,确实,那似乎更有道理。我会纠正我的答案。 - Yannick Motton
使用以下命令进行重定向 $command = 'mysql_tzinfo_to_sql /usr/share/zoneinfo | mysql mysql 2> /dev/null'; 仍然会产生相同的输出。但是,像这样调用我的脚本 php mysql_timezones.php 2> /dev/null 可以正确地抑制输出。是否可能以不同的方式调用我的脚本来达到相同的结果? - JamesArmes
1
尝试使用&> /dev/null。请注意&>之间没有空格。 - Yannick Motton
我刚刚弄明白了这个问题,来到这里想要发布我的发现,结果发现你已经比我先做到了 :-P 确实是 mysql_tzinfo_to_sql 输出了错误信息而不是 mysql。感谢所有回复的人! - JamesArmes
在Windows上返回“系统找不到指定的路径”。 - vee

12

只需将stderr重定向到/dev/null

$command = 'mysql_tzinfo_to_sql /usr/share/zoneinfo | mysql mysql 2>/dev/null';

或输出到 stdout

$command = 'mysql_tzinfo_to_sql /usr/share/zoneinfo | mysql mysql 2>&1';

4

重定向到/dev/null不会使PHP停止等待命令。添加"&"会这样做,你可能将两者联系起来,因为最终的"&"经常与重定向一起使用。

针对Yannick(已删除)的评论回应:如果您想在PHP中后台运行某些内容,则必须同时使用重定向和"&"。但是,这并不意味着仅通过重定向就能使其在后台运行。


根据PHP手册的说明:“如果使用此函数启动程序,为了使其在后台继续运行,程序的输出必须被重定向到文件或另一个输出流。如果未能这样做,PHP将一直挂起,直到程序执行结束。”尽管你的观点似乎是正确的,但PHP需要同时使用重定向和后台运算符&。 - JamesArmes
JamesArmes:这正是我回答的第二部分想要解释的内容。 - Ben James

1

1
这就是exec()调用中的$output变量应该做的事情(它是通过引用传递的)。我尝试使用shell_exec(),并且产生了相同的结果。 - JamesArmes

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接