从Perl调用系统命令 [英] Calling system commands from Perl
问题描述
在我们较旧版本的代码中,我们从Perl中调用以进行LDAP搜索,如下所示:
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
}
上面的代码将导致LDAP搜索成功,并且该搜索的输出将在文件$lworkfile
中.
The code above would result in a successful LDAP search, and the output of that search would be in the file $lworkfile
.
不幸的是,我们最近在此服务器上重新配置了openldap,以便在/etc/openldap/ldap.conf和/etc/ldap.conf中指定"BASE DC =.该更改似乎意味着ldapsearch忽略了LDAP_BASEDN环境变量,因此我的ldapsearch失败了.
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)我尝试返回对ldapsearch使用"-b"参数,但转义了外壳元字符.我开始编写转义代码:
(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;
这引发了一些Perl错误,因为我没有在Perl中正确地转义那些正则表达式(行号与带有反引号的正则表达式匹配).
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)然后,我看到了一些Stackoverflow问题(此处和此处)建议更好的解决方案.
(2) I then saw some Stackoverflow questions (here and here) that suggested a better solution.
这是代码:
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;
我在方法(2)中遇到的两个问题是:
The two problems I am having with approach (2) are:
a)用参数数组调用open或system不允许我将> $lworkfile 2>&1
传递给命令,因此我无法停止将ldapsearch输出发送到屏幕,这会使我的输出看起来很丑陋:
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)我不知道如何选择传递给open
的文件句柄的位置(即路径和文件名),即我不知道$lldap_output
在哪里.我可以移动/重命名它,还是检查它以找出它在哪里(或者它实际上没有保存到磁盘上)?
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)?
基于(2)的问题,这使我认为我应该回到方法(1),但是我不太确定该怎么做
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
推荐答案
一种方法是使用 IPC::Open3
使您的Perl代码能够处理外部程序的stdout和stderr流.
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屋!