【问题标题】:Result form crontab is not same as manually execute?结果形式 crontab 与手动执行不一样?
【发布时间】:2013-08-28 19:16:29
【问题描述】:

我有一个执行一些 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

对此问题的任何想法,并提前感谢您。

【问题讨论】:

    标签: php linux shell crontab


    【解决方案1】:

    有几点值得注意:

    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,在您的情况下可能值得一看:

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

    重要的是,当您手动运行该命令时,它可以访问您登录时加载的所有环境变量(以及在您的.profile.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
    

    这就是我解决an old question of mine 遇到的环境变量未设置问题的方法

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

    【讨论】:

      【解决方案2】:

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

      【讨论】:

      • @Guilgamos:也许,但是哪个用户正在运行脚本?它属于哪个组?是否需要sudo 来运行与网络相关的命令?毕竟,这在 *NIX 系统上并非不可能
      • 如果您在命令行中运行脚本,该脚本将使用当前用户权限。如果脚本由 crontab 运行 - 具有 crontab 文件所属用户的权限。使用 crontab -l -u username 显示某个用户的 crontab 文件
      猜你喜欢
      • 1970-01-01
      • 2017-01-21
      • 2015-09-23
      • 1970-01-01
      • 2017-08-26
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2018-10-06
      相关资源
      最近更新 更多