Berny's Knowledgebase als Newsfeed

Perl wird häufig verwendet, um Aufgaben der Systemadmistration zu automatisieren. Dabei ist es oft nötig, externe Programme aufzurufen. Mit den üblichen Varianten hat man das Problem, dass man entweder die Ausgaben des Programms (STDOUT bzw. STDERR) in eine Variable zugewiesen bekommt oder den Returncode, niemals aber beides. Man muss sich schon entscheiden:

open

Mit dem klassischen open kommt man wunderbar an die Ausgaben des Programms, aber der Returncode ist nicht direkt abfragbar. Man kann höchstens mit Abbruch o. ä. reagieren, z. B. mit einer "or die" Konstruktion.

Wir basteln uns mal ein kleines Beispiel-Script, das einen beliebigen String (der irgendwie wie eine Datumsangabe aussieht) mit Hilfe des date-Kommandos auswerten soll, und falls erfolgreich den Zeitstempel im Unix-Time-Format (Sekunden seit 1.1.1970) zurückgibt.

perl-command-open.pl:
#!/usr/bin/perl

use strict;

my (@linesArray, $line);
my $cmd='date -d "Tue Nov  2 19:59:37 CET 2010" +%s';

open(CMD, "$cmd |")
        @linesArray = <CMD>;
close(CMD);

foreach $line (@linesArray)
{
        print "found line: $line";
}
Ausführung:
booboo@dunno ~/bin % ./perl-command-open.pl
found line: 1288724377
booboo@dunno ~/bin %

system

Beim Aufruf mit system bekommen wir zwar den Returncode, die eigentliche Ausgabe landet aber direkt auf STDOUT und steht somit nicht zur weiteren Verarbeitung im Script in einer Variable zur Verfügung.

perl-command-system.pl:
#!/usr/bin/perl

use strict;

my ($RC);
my $cmd='date -d "Tue Nov  2 19:59:37 CET 2010" +%s';

$RC = system($cmd);

print "returncode was $RC\n";
Ausführung:
booboo@dunno ~/bin % ./perl-command-system.pl
1288724377
returncode was 0
booboo@dunno ~/bin %

Returncode und STDOUT in Variablen

Oft gibt es jedoch Situationen, wo man beides bräuchte: Sowohl den Returncode als auch die Ausgabe in Variablen.

Die Lösung - wiederum an unserem zugegebenermassen etwas konstruierten date-Beispiel - sieht so aus, dass man die Backtrick-Operators kombiniert mit der internen Variable ${^CHILD_ERROR_NATIVE}, die es seit Perl 5.10 gibt.

perl-command-execution-rc-and-output.pl:
#!/usr/bin/perl

use strict;

my $result;

$result = evaluateDate("Tue Nov  2 19:59:37 CET 2010");
print "result: $result\n\n";
$result = evaluateDate("Di 2. Nov 19:59:37 CET 2010");
print "result: $result\n\n";

sub evaluateDate
{
        my $datestring = shift;

        my $dateInSeconds = `date -d "$datestring" +%s 2>&1`;
        my $RC = ${^CHILD_ERROR_NATIVE}/256;
        chomp($dateInSeconds);

        print STDERR "DEBUG: the result is: $dateInSeconds\n";
        print STDERR "DEBUG: returncode was: $RC\n";
        if ($RC eq 0)
        {
                return($dateInSeconds);
        }
        else
        {
                return(-1);
        }
}
Ausführung:
booboo@dunno ~/bin % ./perl-command-execution-rc-and-output.pl
DEBUG: the result is: 1288724377
DEBUG: returncode was: 0
result: 1288724377

DEBUG: the result is: date: ungültiges Datum "Di 2. Nov 19:59:37 CET 2010"
DEBUG: returncode was: 1
result: -1

booboo@dunno ~/bin %