Wenn eine signifikante Ausgabe in stdout und/oder stderr geschrieben wird oder Sie sowohl lesen als auch in den Prozess schreiben. Sie müssen viel vorsichtiger mit Ihrer E/A-Handhabung umgehen, um verschiedene Blockierungsprobleme zu vermeiden.
my ($wtr, $rdr, $err) ;
my $pid = IPC::Open3::open3($wtr, $rdr, $err, @_);
close($wtr);
my $stdout = '';
my $stderr = '';
my $s = IO::Select->new;
$s->add($rdr) if $rdr;
$s->add($err) if $err;
while (my @ready = $s->can_read) {
foreach my $ioh (@ready) {
my $bytes_read = sysread($ioh, my $chunk = '', 1024);
die "read error: $!" unless $bytes_read >= 0;
if ($bytes_read) {
($ioh eq $rdr? $stdout: $stderr) .= $chunk;
}
else {
$s->remove($ioh);
}
}
}
my $pid1;
for (;;) {
last if kill(0, $pid);
$pid1 = wait();
#
# Wait until we see the process or -1 (no active processes);
#
last if ($pid1 == $pid || $pid1 <= 0);
}
Beenden Sie das Lesen, bevor Sie den Prozess beenden. Wenn Sie in die stdin des Prozesses schreiben, müssen Sie auch $ wtr und syswrite zur obigen Auswahlschleife hinzufügen.
EDIT
Begründung:
Die oben ist wahrscheinlich übertrieben für einfache Fälle. Diese erweiterte Handhabung von Eingabe und Ausgabe kommt ins Spiel, wenn Sie wahrscheinlich mehr als ein paar K Daten bewegen.
Sie würden es nicht benötigen, wenn Sie zum Beispiel einen Befehl 'df' ausführen würden.
Wenn jedoch Systempuffer für stdin, stdout oder stderr auffüllen, wird die Blockierung wahrscheinlich und die Dinge können mehr involviert werden.
Wenn der untergeordnete Prozess die Puffer stderr und/oder stdout füllt, wird er wahrscheinlich blockiert und darauf gewartet, dass Sie ihn löschen. Aber wenn Sie auf den Prozess warten, bevor Sie von stdout oder stderr lesen; Das ist eine Sackgasse. Sie werden wahrscheinlich feststellen, dass der Systemaufruf nie beendet wird und der untergeordnete Prozess nie abgeschlossen wird.
Es gibt eine ähnliche Möglichkeit des Deadlocks, wenn in stdin geschrieben wird, aber der untergeordnete Prozess kann die Eingabe nicht verarbeiten. Dies ist besonders wahrscheinlich in einer Pipe-Situation, in der der Child-Prozess Input verbraucht und in stdout schreibt.
Die Auswahlschleife löscht die Puffer progressiv, um Blockierungen zu vermeiden. Sowohl stdout als auch stderr werden gleichzeitig überwacht.
Wenn Sie in stdin schreiben und von stdout (einer Pipe) lesen, sollten Sie stdout und stderr deaktivieren und nur in stdin schreiben, wenn es bereit ist, Eingaben zu empfangen.
Einfach warten auf den Prozess zu beenden, dann funktioniert das Lesen von stdout/stderr wahrscheinlich 90% der Zeit. Diese Antwort dient nur dazu, Ihnen einen Ort zu geben, an den Sie gehen können, wenn die Dinge komplizierter werden und die Prozesse zu blockieren beginnen oder in eine Sackgasse geraten.
EDIT2
Wie für die Verwendung zu, würde ich sagen, beginnen einfach, Test hart.
Gehen Sie mit Sorpigals Ansatz, aber versuchen Sie, Test mit höheren Datenmengen und unter schwierigeren Lasten und Bedingungen, die Sie jemals in einem Live-System erwarten würde.
+1 für die Angabe der Referenz im Perl Doc und die Bereitstellung der Antwort. –
Kopieren/Einfügen von Dokumentation für Spaß und Profit ... – Sorpigal
+1 Danke. Können Sie dies erweitern, um zu überprüfen, ob der Rückgabewert von 'test_app' gültig ist (z. B.' 0', wie in 'capture ([0], ...)')? –