4

コードの古いバージョンでは、次のように 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」引数を使用することに戻ろうとしましたが、シェルのメタ文字をエスケープしました。私はエスケープコードを書き始めました:

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 の質問 (ここここ) を見ました。

コードは次のとおりです。

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)で私が抱えている2つの問題は次のとおりです。

a) 引数の配列を指定して open または system を呼び出す> $lworkfile 2>&1と、コマンドに渡すことができないため、ldapsearch の出力が画面に送信されるのを止めることができず、出力が見苦しくなります。

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

b) に渡されたファイル ハンドルの場所 (つまり、パスとファイル名) を選択する方法がopenわかりません。つまり、場所がわかりません$lldap_output。移動/名前変更、または検査してどこにあるか (または実際にディスクに保存されていないか) を調べることはできますか?

(2)の問題に基づいて、これは(1)のアプローチに戻るべきだと思いますが、どうすればよいかわかりません

4

5 に答える 5

4

1 つのアプローチはIPC::Open3、Perl コードが外部プログラムの stdout ストリームと stderr ストリームの両方を処理できるようにするために を使用することです。

于 2010-12-10T21:13:23.927 に答える
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}.

于 2010-12-10T21:58:55.920 に答える
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;
于 2010-12-12T23:41:45.887 に答える
0

単純な「open」を使用して、複数の引数を持つ外部プログラムから STDOUT と 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 を読み取るだけで、STDOUT と STDERR の両方を取得できます。

于 2015-04-22T06:01:15.047 に答える
0

openのドキュメントを参照してください。STDERR を複製してリダイレクトし、コマンドを実行してから、STDERR を復元できます。IPC::(Open3、Run、Run3 など) ライブラリを使用するよりも冗長ですが、追加のモジュールをインストールできない/インストールしない場合、または IPC を使用したくない場合は、ライブラリを使用しなくてもかまいません。 ::Open3.

于 2010-12-31T21:46:58.210 に答える