从 Perl 调用系统命令 [英] Calling system commands from Perl

查看:23
本文介绍了从 Perl 调用系统命令的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

在我们的代码的旧版本中,我们从 Perl 调用执行 LDAP 搜索,如下所示:

# 通过 ldapsearch-specific 环境变量传入基本 DN#(而不是作为-b"参数)以避免shell问题# DN 中特殊字符的解释.$ENV{LDAP_BASEDN} = $ldn;$lcmd = "ldapsearch -x -T -1 -h $gLdapServer" .<剪辑>">$lworkfile 2>&1";系统($ lcmd);if (($?!= 0) || (!-e "$lworkfile")){# 处理错误}

上面的代码将导致成功的 LDAP 搜索,并且该搜索的输出将在文件 $lworkfile 中.

不幸的是,我们最近在此服务器上重新配置了 openldap,以便在/etc/openldap/ldap.conf 和/etc/ldap.conf 中指定BASE DC=".这种变化似乎意味着 ldapsearch 忽略了 LDAP_BASEDN 环境变量,所以我的 ldapsearch 失败了.

我尝试了几种不同的修复方法,但到目前为止都没有成功:

(1) 我尝试回到使用 ldapsearch 的-b"参数,但转义了 shell 元字符.我开始写转义代码:

我的 $ldn_escaped = $ldn;$ldn_escaped =~ s//\/g;$ldn_escaped =~ s/`/`/g;$ldn_escaped =~ s/$/$/g;$ldn_escaped =~ s/"/"/g;

这引发了一些 Perl 错误,因为我没有在 Perl 中正确地转义这些正则表达式(行号与带有反引号的正则表达式匹配).

<块引用>

在/tmp/mycommand line 404 处的操作员预期的位置找到反引号,在行尾

同时我开始怀疑这种方法并寻找更好的方法.

(2) 然后我看到了一些 Stackoverflow 问题(这里这里)更好的解决方案.

代码如下:

print("处理中...");# 通过使用数组调用 open() 将参数传递给 ldapsearch.# 这确保 shell 不会解释 shell 元字符.我的(@cmd_args)=(-x",-T",-1",-h",$gLdapPool",-b",$ldn",<剪辑>);$lcmd = "ldapsearch";打开我的 $lldap_output, "-|", $lcmd, @cmd_args;而(我的 $lline = <$lldap_output>){# 我可以很好地解析我的文件的内容}$lldap_output->关闭;

我在方法 (2) 中遇到的两个问题是:

a) 使用参数数组调用 open 或 system 不允许我通过 >$lworkfile 2>&1 到命令,所以我无法停止将 ldapsearch 输出发送到屏幕,这使我的输出看起来很难看:

<块引用>

处理中...ldap_bind: 成功 (0)附加信息:成功

b) 我不知道如何选择传递给 open 的文件句柄的位置(即路径和文件名),即我不知道 $lldap_output 在哪里 是.我可以移动/重命名它,或者检查它以找出它在哪里(或者它实际上没有保存到磁盘)吗?

基于(2)的问题,这让我觉得我应该回到方法(1),但我不太确定如何

解决方案

一种方法是使用 IPC::Open3 使您的 Perl 代码能够处理外部程序的 stdout 和 stderr 流.

In an older version of our code, we called out from Perl to do an LDAP search as follows:

# Pass the base DN in via the ldapsearch-specific environment variable 
# (rather than as the "-b" paramater) to avoid problems of shell 
# interpretation of special characters in the DN.
$ENV{LDAP_BASEDN} = $ldn;

$lcmd = "ldapsearch -x -T -1 -h $gLdapServer" .
        <snip>
        " > $lworkfile 2>&1";
system($lcmd);

if (($? != 0) || (! -e "$lworkfile"))
{
  # Handle the error
}

The code above would result in a successful LDAP search, and the output of that search would be in the file $lworkfile.

Unfortunately, we recently reconfigured openldap on this server so that a "BASE DC=" is specified in /etc/openldap/ldap.conf and /etc/ldap.conf. That change seems to mean ldapsearch ignores the LDAP_BASEDN environment variable, and so my ldapsearch fails.

I've tried a couple of different fixes but without success so far:

(1) I tried going back to using the "-b" argument to ldapsearch, but escaping the shell metacharacters. I started writing the escaping code:

my $ldn_escaped = $ldn;
$ldn_escaped =~ s//\/g;
$ldn_escaped =~ s/`/`/g;
$ldn_escaped =~ s/$/$/g;
$ldn_escaped =~ s/"/"/g;

That threw up some Perl errors because I haven't escaped those regexes properly in Perl (the line number matches the regex with the backticks in).

Backticks found where operator expected at /tmp/mycommand line 404, at end of line

At the same time I started to doubt this approach and looked for a better one.

(2) I then saw some Stackoverflow questions (here and here) that suggested a better solution.

Here's the code:

print("Processing...");

# Pass the arguments to ldapsearch by invoking open() with an array.
# This ensures the shell does NOT interpret shell metacharacters.
my(@cmd_args) = ("-x", "-T", "-1", "-h", "$gLdapPool",
                 "-b", "$ldn",
                 <snip>
                );

$lcmd = "ldapsearch";

open my $lldap_output, "-|", $lcmd, @cmd_args;

while (my $lline = <$lldap_output>)
{
  # I can parse the contents of my file fine
}

$lldap_output->close;

The two problems I am having with approach (2) are:

a) Calling open or system with an array of arguments does not let me pass > $lworkfile 2>&1 to the command, so I can't stop the ldapsearch output being sent to screen, which makes my output look ugly:

Processing...ldap_bind: Success (0)
        additional info: Success

b) I can't figure out how to choose which location (i.e. path and file name) to the file handle passed to open, i.e. I don't know where $lldap_output is. Can I move/rename it, or inspect it to find out where it is (or is it not actually saved to disk)?

Based on the problems with (2), this makes me think I should return back to approach (1), but I'm not quite sure how to

解决方案

One approach would be to use IPC::Open3 to enable your Perl code to handle both the stdout and stderr streams of your external program.

这篇关于从 Perl 调用系统命令的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆