在旧版本的代码中,我们从Perl调出来进行LDAP搜索,如下所示:
# 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
中。
不幸的是,我们最近在此服务器上重新配置了openldap,以便在/etc/openldap/ldap.conf和/etc/ldap.conf中指定“BASE DC =”。这种变化似乎意味着ldapsearch忽略了LDAP_BASEDN环境变量,因此我的ldapsearch失败了。
到目前为止,我尝试了几种不同的修复但没有成功:
(1)我尝试回到ldapsearch使用“-b”参数,但是转义shell元字符。我开始编写转义代码:
my $ldn_escaped = $ldn;
$ldn_escaped =~ s/\/\\/g;
$ldn_escaped =~ s/`/\`/g;
$ldn_escaped =~ s/$/\$/g;
$ldn_escaped =~ s/"/\"/g;
这引发了一些Perl错误,因为我没有在Perl中正确地转义那些正则表达式(行号与带有反引号的正则表达式相匹配)。
Backticks found where operator expected at /tmp/mycommand line 404, at end of line
与此同时,我开始怀疑这种方法并寻找更好的方法。
(2)然后我看到一些Stackoverflow问题(here和here)提出了更好的解决方案。
以下是代码:
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)的两个问题是:
a)使用参数数组调用open或system不允许我将> $lworkfile 2>&1
传递给命令,因此我无法停止将ldapsearch输出发送到屏幕,这使得我的输出看起来很丑:< / p>
Processing...ldap_bind: Success (0) additional info: Success
b)我无法弄清楚如何选择传递给open
的文件句柄的位置(即路径和文件名),即我不知道$lldap_output
在哪里。我可以移动/重命名它,或检查它以找出它的位置(或者它实际上没有保存到磁盘)?
基于(2)的问题,这让我觉得我应该回到方法(1),但我不太确定如何
答案 0 :(得分:4)
一种方法是使用IPC::Open3
使您的Perl代码能够处理外部程序的stdout和stderr流。
答案 1 :(得分:2)
我会使用IPC::Run3。这很像open '-|'
方法,但允许您重定向STDERR。
注意:$lldap_output
是从ldapsearch
读取的管道。磁盘上没有创建文件。
如果你想要一个磁盘上的文件,你可以像这样使用IPC :: Run3:
use IPC::Run3;
my ($lcmd, @cmd_args) = ... # same as approach (2) above
my $lworkfile = ... # same as approach (1) above
run3 [ $lcmd, @cmd_args ], undef, $lworkfile, $lworkfile;
这类似于方法(1),但使用-b
代替$ENV{LDAP_BASEDN}
。
答案 2 :(得分:0)
感谢Greg Hewgill的回答。我在下面发布我的代码,以防其他人想要使用open3函数。
use File::Copy;
use IPC::Open3;
# 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";
my $lldap_output;
# First arg is undef as I don't need to pass any extra input to the
# process after it starts running.
my $pid = open3(undef, $lldap_output, $lldap_output, $lcmd, @cmd_args);
# Wait for the process to complete and then inspect the return code.
waitpid($pid, 0);
my $ldap_retcode = $? >> 8;
if ($ldap_retcode != 0)
{
# Handle error
}
# Copy the output to $lworkfile so I can refer to it later if needed
copy($lldap_output, $lworkfile);
while (my $lline = <$lldap_output>)
{
# I can parse the contents of my file fine
}
$lldap_output->close;
答案 3 :(得分:0)
请参阅open的文档。您可以复制并重定向STDERR,运行命令,然后恢复STDERR。它比使用任何IPC ::(Open3,Run,Run3等)库更冗长,但如果你不能/不会安装额外的模块,或者不想使用IPC,可能没有它们:: Open3。
答案 4 :(得分:0)
这是一种使用普通ol&#39;从具有多个参数的外部程序读取STDOUT和STDERR的hacky方法。 &#34;开&#34;:
my @command_with_arguments = (YOUR_PROGRAM, ARG1, ARG2, ARG3);
foreach(@command_with_arguments){s/'/'"'"'/g;}
foreach(@command_with_arguments){s/(.+)/'$1'/;}
my $run_command = join (' ', @command_with_arguments) . " 2>&1 |";
open my $program_output, $run_command;
现在只需读取$ program_output即可获得STDOUT和STDERR。