2010-12-10 74 views
4

命令在舊版本的我們的代碼,我們從Perl的叫出來做一個LDAP搜索如下:系統調用在Perl

# 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)我想回去使用「-b」參數ldapsearch的,但逃脫了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問題(herehere),這表明提供了一個更好的解決方案。

下面的代碼:

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):

一)調用打開或系統參數數組不會讓我過去> $lworkfile 2>&1到命令,所以我不能停止ldapsearch的輸出發送到屏幕上,這讓我的輸出看起來很醜陋:

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

b)我不知道如何選擇哪個位置(即路徑和文件名稱)傳遞給傳遞給open的文件句柄,即我不知道$lldap_output在哪裏。我可以移動/重命名它,還是檢查它以找出它的位置(或它是否實際上未保存到磁盤)?

根據與(2),這讓我覺得我應該返回到方法(1),但我不是很清楚如何

回答

4

一種方法是使用IPC::Open3,使您的問題Perl代碼來處理外部程序的stdout和stderr流。

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}

+0

這是在覈心Perl模塊?該解決方案看起來不錯,但不幸的是,Perl報告「無法在@INC中找到IPC/Run3.pm」。我猜我需要安裝這個IPC-Run3-0.044模塊,我寧願避免這樣做,因爲我必須對服務器進行構建/安裝更改。 – 2010-12-10 22:28:57

+0

不,IPC :: Run3不是核心模塊。 – cjm 2010-12-10 22:58:31

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; 
0

請參閱該文檔爲open。您可以複製並重定向STDERR,運行命令,然後恢復STDERR。它比使用任何IPC的更冗長::(Open3,Run,Run3等)庫,但如果你不能/不會安裝額外的模塊或不想使用IPC :: Open3。

+0

這會很好,但你真的設法做到這一點嗎?我運行命令時無法重定向:打開DUP,「>&STDERR」;打開DUP,「>」,「duperr.txt」;打開COMMAND,「 - |」,$ my_command;打開STDERR,「> DUP_STDERR」; – schulwitz 2015-04-22 04:27:17

+0

@schulwitz:你正在恢復到錯誤的文件句柄,並且做得不正確,應該是'open STDERR,>&DUP「' – runrig 2017-11-21 00:09:08

+0

此外,你複製stderr,但是然後打開重複的文件...你需要打開STDERR到文件。 – runrig 2017-11-21 00:10:15

0

這裏的閱讀與使用純醇」‘打開’多個參數標準輸出和STDERR從外部程序哈克的方式:

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獲得標準輸出和STDERR。