1

我有一个执行一些 shell 命令的 PHP 脚本。

一旦我手动执行它。它工作得很好。

但是我使用crontab执行后,一些shell命令的结果丢失了。

这是 2 个命令。

  • ip route
  • iptables -t nat -L | grep 8800

这是一个示例 PHP 代码。

#!/usr/bin/php -q
<?
    $route = exec('ip route');
    $iptable = exec('iptables -t nat -L | grep 8800');
    echo $route;
    echo $iptables;
?>

上面的代码适用于手动执行,但不适用于 crontab。

我发现有些命令两者都适用。例如

  • ifconfig eth0 | grep 'inet addr:' | cut -d: -f2 | awk '{ print $1}'
  • cat /tmp/example | grep test

对此问题的任何想法,并在此先感谢您。

4

2 回答 2

4

有几点值得注意:

exec函数的签名是

string exec ( string $command [, array &$output [, int &$return_var ]] )

要获得命令的完整输出,您必须像这样调用它:

$output = array();//declare in advance is best because:
$lastLine = exec('ip route', $status, $output);//signature shows reference expected
print_r($output);//full output, array, each index === new line
echo PHP_EOL, 'The command finished ', $status === 0 ? 'well' : 'With errors: '.$status;

您正在使用该exec命令,就好像它是passthru,在您的情况下可能值得一看:

命令结果的最后一行。如果您需要执行命令并将命令中的所有数据直接传回而不受任何干扰,请使用passthru() 函数

重要的是,当您手动运行命令时,它可以访问您登录时加载的所有环境变量(以及在您的.profileor.basrc文件中设置的任何其他变量)。使用 crontab 或通过 ssh 运行命令时,情况并非如此。
也许,$PATH环境变量已设置为您无权访问ip其他命令。对此有简单的修复:

exech('/sbin/ip route');//if that's the correct path

或者,准备好第二个脚本,并将您的 PHP 脚本更改为:

if (!exec('which ip'))
{//ip command not found
    return exec('helper.sh '.implode(' ', $argv));//helper script
}

辅助脚本如下所示:

#/bin/bash
source /home/user/.bashrc
$*

只是$*再次调用原始 PHP 脚本,只是这一次,配置文件已加载。您可以将source调用替换为export PATH=$PATH:/sbin或其他内容,然后按照您需要的方式设置环境变量。

第三部分也是最后一部分使用管道和proc_open. 这是加载配置文件并递归调用脚本的仅 PHP 方式:

if(!$_SERVER['FOO'])
{//where FOO is an environment variable that is loaded in the .profile/.bashrc file
    $d = array(array('pipe','r'),array('pipe','w'));
    $p = proc_open('ksh',$d,$pipes);
    if(!is_resource($p) || end($argv) === 'CalledFromSelf')
    {//if the last argument is calledFromSelf, we've been here before, and it didn't work
        die('FFS');//this is to prevent deadlock due to infinite recursive self-calling
    }
    fwrite($pipes[0],'source /home/user/.profile'."\n");
    fwrite($pipes[0],implode(' ',$argv).' CalledFromSelf'."\n");
    fclose($pipes[0]);
    usleep(15);//as long as you need
    echo stream_get_contents($pipes[1]);
    fclose($pipes[1]);
    proc_close($p);
    exit();
}
echo $_SERVER['FOO'].PHP_EOL;//actual script goes here, we can use the FOO env var

这就是我解决我的一个老问题的方法,我遇到了未设置环境变量的困难

最后要注意的是:运行 crontab 的用户是否具有执行需要执行的操作所需的权限?

于 2013-08-26T10:39:06.350 回答
0

注意运行脚本的用户。可能是用户(您添加 crontab 任务)没有足够的权限。

于 2013-08-26T10:21:15.107 回答