2009-11-17 12 views
9

Ich habe derzeit ein Perl-Skript, das einen externen Befehl auf dem System ausführt, sammelt die Ausgabe und führt eine Aktion basierend auf was zurückgegeben wurde. Gerade jetzt, hier ist, wie ich laufen diese (wobei $ cmd ein String mit dem Befehl Setup ist):Wie kann ich einen Systembefehl in Perl asynchron ausführen?

@output = `$cmd`; 

Ich würde dies gerne so ändern, wenn der Befehl hängt und gibt keinen Wert nach so viel Zeit dann töte ich den Befehl. Wie würde ich das asynchron ausführen?

Antwort

8

Wenn Sie wirklich nur eine Zeitüberschreitung für einen bestimmten Systemaufruf setzen müssen, ist das ein viel einfacheres Problem als die asynchrone Programmierung.

Alles, was Sie brauchen, ist Alarm() in einem eval() - Block.

Hier ist ein Beispielcode-Block, der diese in eine Unterroutine steckt, die Sie in Ihren Code einfügen können. Das Beispiel ruft Schlaf so für die Ausgabe nicht aufregend ist, aber Sie nicht zeigen, die Timeout-Funktionalität, die Sie interessierten sich Output es läuft.

/bin/Schlaf 2 failure: Timeout bei ./time -out Linie 15.

$ cat time-out 
#!/usr/bin/perl 

use warnings; 
use strict; 
my $timeout = 1; 
my @cmd = qw(/bin/sleep 2); 
my $response = timeout_command($timeout, @cmd); 
print "$response\n" if (defined $response); 

sub timeout_command { 
     my $timeout = (shift); 
     my @command = @_; 
     undef [email protected]; 
     my $return = eval { 
       local($SIG{ALRM}) = sub {die "timeout";}; 
       alarm($timeout); 
       my $response; 
       open(CMD, '-|', @command) || die "couldn't run @command: $!\n"; 
       while(<CMD>) { 
         $response .= $_; 
       } 
       close(CMD) || die "Couldn't close execution of @command: $!\n"; 
       $response; 
     }; 
     alarm(0); 
     if ([email protected]) { 
       warn "@cmd failure: [email protected]\n"; 
     } 
     return $return; 
} 
+0

Danke, das ist mehr, was ich gesucht habe. – Joel

+0

Ich denke, du brauchst ein \ n in der Würfel Nachricht. (http://perldoc.perl.org/functions/alarm.html) – ddoxey

12

eine Menge Möglichkeiten gibt, dies zu tun:

  • Sie diese mit einer Gabel tun (perldoc -f Gabel)
  • oder mit Gewinden (perldoc Threads). Beides macht die Weitergabe der zurückgegebenen Informationen an das Hauptprogramm schwierig.
  • Auf Systemen, die dies unterstützen, können Sie einen Alarm (perldoc -f-Alarm) einstellen und dann im Signalhandler aufräumen.
  • Sie können eine Ereignisschleife wie POE oder Coro verwenden.
  • Anstelle der Backticks können Sie open() bzw. open2 oder open3 (vgl. IPC :: Open2, IPC :: Open3) verwenden, um ein Programm zu starten, während Sie STDOUT/STDERR über ein Datei-Handle erhalten. Führen Sie nicht blockierende Lesevorgänge für sie aus. (perldoc -f select und wahrscheinlich google "perl nonblocking lesen")
  • Als eine leistungsfähigere Variante der openX() ', überprüfen Sie IPC :: Run/IPC :: Cmd.
  • Wahrscheinlich Tonnen, an die ich mitten in der Nacht nicht denken kann.
+3

auf win32-Systemen achten Sie auf gebrochene 'select', die nur für Steckdosen und möglicherweise seltsame Interaktionen mit Konsolenfenster, wperl (läuft perl in einer nicht-Konsolenfenster Art und Weise funktioniert, hat aber seltsame Auswirkungen auf STDIO und Child-Prozesse). Auf der positiven Seite können Sie ein 'System (-1, 'foo')' 'machen. Einige Methoden zum Starten eines Prozesses schlagen nach dem Ausführen von 64 Kindern fehl. IME, 'Win32 :: Process :: Create()' ist der sicherste Weg, ein Programm im bgrnd auszuführen. – daotoad

+0

@daotoad, danke für diesen Kommentar.Mein Mangel an win32-Hinweis zeigt, dass das einzige, was ich weiß, ist, dass fork() mit Threads emuliert wird und Sie keinen Alarm verwenden können. Ich denke, wenn Win32 beteiligt ist, wäre IPC :: Cmd eine gute Wahl. – tsee

1

Wenn Ihr externes Programm nicht jede Eingabe nicht nehmen, achten Sie auf die folgenden Wörter in der perlipc manpage:

Hier ist eine sichere Graviszeichen oder Rohr offen für Lese:

Verwenden Das Beispielcode und schützen Sie es mit einem Alarm (der auch in perlipc erklärt wird).

Verwandte Themen