4 Stimmen

Aufrufen von Systembefehlen aus Perl

In einer älteren Version unseres Codes haben wir von Perl aus eine LDAP-Suche wie folgt durchgeführt:

# 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
}

Der obige Code würde zu einer erfolgreichen LDAP-Suche führen, und die Ausgabe dieser Suche würde in der Datei $lworkfile .

Leider haben wir openldap auf diesem Server kürzlich neu konfiguriert, so dass in /etc/openldap/ldap.conf und /etc/ldap.conf ein "BASE DC=" angegeben ist. Diese Änderung scheint zu bedeuten, dass ldapsearch die Umgebungsvariable LDAP_BASEDN ignoriert, so dass meine ldapsearch fehlschlägt.

Ich habe verschiedene Lösungen ausprobiert, aber bisher ohne Erfolg:

(1) Ich habe versucht, wieder das Argument "-b" für ldapsearch zu verwenden, aber die Shell-Metazeichen zu escapen. Ich habe angefangen, den Escaping-Code zu schreiben:

my $ldn_escaped = $ldn;
$ldn_escaped =~ s/\/\\/g;
$ldn_escaped =~ s/`/\`/g;
$ldn_escaped =~ s/$/\$/g;
$ldn_escaped =~ s/"/\"/g;

Das führte zu einigen Perl-Fehlern, weil ich diese Regexe in Perl nicht richtig escaped habe (die Zeilennummer stimmt mit der Regex mit den Backticks überein).

Backticks found where operator expected at /tmp/mycommand line 404, at end of line

Gleichzeitig begann ich an diesem Ansatz zu zweifeln und suchte nach einer besseren Lösung.

(2) Ich habe dann einige Stackoverflow-Fragen gesehen ( aquí y aquí ), die eine bessere Lösung vorschlug.

Hier ist der Code:

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;

Die beiden Probleme, die ich mit Ansatz (2) habe, sind:

a) Der Aufruf von open oder system mit einem Array von Argumenten erlaubt mir nicht die Übergabe von > $lworkfile 2>&1 an den Befehl angehängt, so dass ich nicht verhindern kann, dass die ldapsearch-Ausgabe an den Bildschirm gesendet wird, was meine Ausgabe hässlich aussehen lässt:

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

b) Ich kann nicht herausfinden, wie ich den Speicherort (d.h. Pfad und Dateiname) für das Dateihandle auswählen kann, das an open d.h. ich weiß nicht, wo $lldap_output ist. Kann ich sie verschieben/umbenennen oder untersuchen, um herauszufinden, wo sie sich befindet (oder ist sie gar nicht auf der Festplatte gespeichert)?

Angesichts der Probleme mit (2) denke ich, dass ich zu Ansatz (1) zurückkehren sollte, aber ich bin mir nicht ganz sicher, wie

4voto

Greg Hewgill Punkte 882617

Ein Ansatz wäre die Verwendung von IPC::Open3 um Ihren Perl-Code in die Lage zu versetzen, sowohl den stdout- als auch den stderr-Stream Ihres externen Programms zu verarbeiten.

2voto

cjm Punkte 60581

Ich würde verwenden IPC::Lauf3 für diese. Dies ist ähnlich wie die open '-|' Ansatz, erlaubt es aber auch, STDERR umzuleiten.

Anmerkung: $lldap_output ist ein Rohr, das von ldapsearch . Es wird keine Datei auf der Festplatte erstellt.

Wenn Sie eine Datei auf der Festplatte wünschen, können Sie IPC::Run3 wie folgt verwenden:

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;

Dies entspricht dem Ansatz (1), aber mit -b anstelle von $ENV{LDAP_BASEDN} .

1voto

Dan J Punkte 24945

Vielen Dank an Greg Hewgill für die Antwort. Ich poste meinen Code unten, falls er anderen hilft, die die Funktion open3 verwenden möchten.

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;

0voto

runrig Punkte 6433

Siehe die Dokumentationen für öffnen . Sie können STDERR duplizieren und umleiten, Ihren Befehl ausführen und dann STDERR wiederherstellen. Es ist ausführlicher als die Verwendung einer der IPC::(Open3, Run, Run3, etc.) Bibliotheken, aber es ist möglich, ohne sie zu tun, wenn Sie keine zusätzlichen Module installieren können/wollen oder IPC::Open3 nicht verwenden wollen.

0voto

schulwitz Punkte 1563

Hier ist ein einfacher Weg, um sowohl STDOUT als auch STDERR von einem externen Programm mit mehreren Argumenten zu lesen, indem man einfach das alte "open" benutzt:

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;

Lesen Sie nun einfach $program_output, um sowohl STDOUT als auch STDERR zu erhalten.

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X