【问题标题】:Bash script hangs when called from php or python从 php 或 python 调用时,Bash 脚本挂起
【发布时间】:2013-09-28 04:25:23
【问题描述】:

我是 bash 的新手,我编写了一个 bash 脚本,它从头到尾读取一个大型 syslog 文件,查找属于给定分钟(最后一分钟前)的条目,然后计算出现次数每个给定的模式在那一分钟都有。 如果从 PHP/Python 运行,它不起作用,但如果我像这样直接调用它,它就会起作用:

sh /path/to/logparser.sh /path/to/big.log '2013-09-23T08:38' '2013-09-23T08:37' 'MySQL has gone away' 'Unhandled Error timed out'

下面是logparser.sh的代码:

logfile=$1
echo $logfile
shift
minute=$1
echo $minute
shift
minute_before=$1
echo $minute_before
shift
command="tac $logfile | sed -n -e '/$minute/p' -e '/$minute_before/q'"
echo $command
if [ -f $logfile ]; then
    buffer=$(eval $command)
    echo "buffer complete"
    exit 1
fi

旁注:

  • 我使用了buffer=$(eval $command),因为buffer=$(tac $logfile | sed -n -e '/$minute/p' -e '/$minute_before/q') 即使在命令行中也会挂起
  • 我在 sed 中使用了 -e '/$minute_before/q',因为我无法让 `-e '/$minute/!q' 工作

但是当我通过pasthru() 从 PHP 或通过subprocess.Popen().communicate() 从 Python 运行它时,它挂起。如果我使用ps -ef r 检查进程,我发现tac 仍在运行。

这是调用 bash 脚本的 PHP 代码:

$env           = $argv[1];
$service_name  = $argv[2];
$logfile       = $argv[3];
$minute        = $argv[4];
$minute_before = $argv[5];

$command = 'sh '.dirname(__FILE__).'/logparser.sh ';

$n = count($argv);
for($i=3; $i<$n; $i++){
    $command .= ' ' . escapeshellarg($argv[$i]);
}
$command .= "\n";
echo "\npassthru {$command}";
passthru($command, $out);
var_dump($out);
exit();

这是调用 bash 脚本的 Python 代码:

env           = sys.argv[1]
service_name  = sys.argv[2]
logfile       = sys.argv[3]
minute        = sys.argv[4]
minute_before = sys.argv[5]

args = ['sh', '%s/logparser.sh' % os.getcwd()]

for i in range(3, len(sys.argv)):
    args.append(sys.argv[i])

print args
output = subprocess.Popen(args, stdout=subprocess.PIPE).communicate()
print output

我排除的其他内容:

  • exec 权限:PHP 和 Python 都可以运行并获取 linux 命令的结果,例如whoami
  • 文件权限:对于更简单的 bash 脚本,PHP 和 Python 都可以完美运行,例如包含date liunx 命令的文件;日志文件对所有人都有读取权限
  • 错误参数:我在 bash 脚本中比较了 PHP/Python 发送的参数和命令行发送的参数,它们是相同的

我怎样才能使它工作从 PHP/Python 调用?

【问题讨论】:

    标签: php python linux bash sed


    【解决方案1】:

    您的任何代码似乎都没有将您的日志文件传递给您的 shell 脚本,日志文件变量在您的 shell 中未设置,从而使 tac 等待来自标准输入的输入。

    就像在你的 python 代码中一样,也许你需要这样做:

    for i in range(1, len(sys.argv)):
        args.append(sys.argv[i])
    

    同样在你的 php 代码中:

    $n = count($argv);
    for($i=1; $i<$n; $i++){
        $command .= ' ' . escapeshellarg($argv[$i]);
    }
    

    日志文件的路径未传递给您的 shell 脚本的实际原因可能不同,但通常这是脚本挂起的基本原因。

    【讨论】:

    • 抱歉,为了简化脚本,我忘记了一些事情:我不需要将 env 和 service_name 传递给 bash 脚本,但我确实需要它们进行一些处理,以防 bash脚本成功。日志文件变量是 argv[3],它被传递给 bash 脚本:如果我复制 echo "\npassthru {$command}"; 的输出并将其粘贴到终端中,它将起作用。
    猜你喜欢
    • 2015-03-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-04-07
    • 2016-04-08
    • 2011-11-18
    • 1970-01-01
    相关资源
    最近更新 更多