从Perl调用系统命令

从Perl调用系统命令,perl,ldap,openldap,Perl,Ldap,Openldap,在旧版本的代码中,我们从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; $lcm

在旧版本的代码中,我们从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
}
这引发了一些Perl错误,因为我没有在Perl中正确地转义这些正则表达式(行号与中的反勾号匹配)

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

(2) 然后我看到了一些Stackoverflow问题(和),这些问题提出了更好的解决方案

代码如下:

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;
b) 我不知道如何选择传递给
open
的文件句柄的位置(即路径和文件名),也就是说,我不知道
$lldap\u输出在哪里。我可以移动/重命名它,或者检查它以找出它在哪里(或者它实际上没有保存到磁盘上)


基于(2)中的问题,这使我认为应该回到方法(1),但我不太确定如何使用一种方法,使您的Perl代码能够处理外部程序的stdout和stderr流。这很像
open'-|'
方法,但也允许重定向STDERR

注意:
$lldap\u输出是从
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\u BASEDN}

感谢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;
使用文件::复制;
使用IPC::Open3;
#通过使用数组调用open()将参数传递给ldapsearch。
#这确保了shell不会解释shell元字符。
my(@cmd_args)=(“-x”、“-T”、“-1”、“-h”、“$gLdapPool”,
“-b”、“$ldn”,
);
$lcmd=“ldapsearch”;
我的$lldap_输出;
#第一个参数是未定义的,因为我不需要向
#进程开始运行后。
my$pid=open3(未定义,$lldap_输出,$lldap_输出,$lcmd,@cmd_参数);
#等待流程完成,然后检查返回代码。
waitpid($pid,0);
我的$ldap\u retcode=$?>>8.
如果($ldap_retcode!=0)
{
#处理错误
}
#将输出复制到$lworkfile,以便以后需要时可以引用它
副本($lldap_输出,$lworkfile);
而(我的$lline=)
{
#我可以很好地解析文件的内容
}
$lldap_输出->关闭;

有关详细信息,请参阅文档。您可以复制和重定向STDERR,运行命令,然后恢复STDERR。它比使用任何IPC:(Open3、Run、Run3等)库都要详细,但如果您不能/不想安装额外的模块,或者不想使用IPC::Open3,则可以不使用它们。

这里有一种黑客方法,可以使用普通的ol“open”从具有多个参数的外部程序中读取STDOUT和STDERR:


现在只需读取$program_输出即可获得STDOUT和STDERR。

这是否在核心Perl模块中?这个解决方案看起来不错,但不幸的是Perl报告“在@INC中找不到IPC/Run3.pm”。我猜我需要安装这个IPC-Run3-0.044模块,我希望避免安装,因为我必须对我们的服务器进行构建/安装更改。不,IPC::Run3不是一个核心模块。这很好,但你真的做到了吗?运行时,命令无法重定向:open DUP,“>&STDERR”;打开DUP,“>”,“duperr.txt”;打开命令“-|”,$my_命令;打开STDERR,“>DUP_STDERR”@schulwitz:您正在还原到错误的文件句柄,并且操作不正确,应该是
open STDERR,“>&DUP”
此外,您复制了STDERR,但随后将副本打开到一个文件…您需要将STDERR打开到该文件。
Processing...ldap_bind: Success (0)
        additional info: Success
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;
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;
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;