Jak przechwycić stderr, stdout i kod wyjścia jednocześnie w Perlu?

Czy jest możliwe uruchomienie zewnętrznego procesu z Perla, przechwycenie jego stderr, stdout i kodu zakończenia procesu?

Wydaje mi się, że jestem w stanie wykonać ich kombinacje, np. użyć backticks, aby uzyskać stdout, IPC::Open3, aby przechwycić wyjścia, i system (), aby uzyskać kody wyjścia.

Jak przechwycić stderr, stdout i kod wyjścia na raz?

Author: DVK, 2008-09-20

6 answers

Jeśli ponownie przeczytasz dokumentację IPC:: Open3, zobaczysz notatkę, którą powinieneś wywołać waitpid , Aby pobrać proces potomny. Gdy to zrobisz, status powinien być dostępny w $?. Wartość wyjściowa to $? >> 8. Zobacz też $? w perldoc perlvar .

 26
Author: Michael Carman,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2009-09-30 17:20:13

(Update : zaktualizowałem API dla IO:: CaptureOutput, aby było to jeszcze łatwiejsze.)

Można to zrobić na kilka sposobów. Oto jedna z opcji, używając modułu IO::CaptureOutput :
use IO::CaptureOutput qw/capture_exec/;

my ($stdout, $stderr, $success, $exit_code) = capture_exec( @cmd );

Jest to funkcja capture_exec (), ale IO::CaptureOutput ma również bardziej ogólną funkcję capture (), która może być użyta do przechwytywania wyjścia Perla lub wyjścia z zewnętrznych programów. Więc jeśli jakiś moduł Perla użyje jakiegoś zewnętrznego programu, nadal otrzymujesz wyjście.

Oznacza to również, że musisz pamiętać tylko jedno podejście do przechwytywania STDOUT i STDERR (lub ich scalania) zamiast używać IPC::Open3 dla zewnętrznych programów i innych modułów do przechwytywania wyjścia Perla.

 41
Author: xdg,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2008-09-21 21:48:13

Jeśli nie chcesz zawartości STDERR, to polecenie capture() z modułu IPC::System::Simple jest prawie dokładnie tym, czego szukasz:

   use IPC::System::Simple qw(capture system $EXITVAL);

   my $output = capture($cmd, @args);

   my $exit_value = $EXITVAL;

Można użyć metody capture () z pojedynczym argumentem do wywołania powłoki lub z wieloma argumentami, aby niezawodnie uniknąć powłoki. Istnieje również funkcja capturex (), która nigdy nie wywołuje powłoki, nawet z jednym argumentem.

W przeciwieństwie do wbudowanych poleceń systemu i backticks w Perlu, IPC:: System:: Simple zwraca pełną 32-bitową wartość wyjściową pod Okna. Rzuca również szczegółowy wyjątek, jeśli polecenie nie może zostać uruchomione, umiera na sygnał lub zwraca nieoczekiwaną wartość zakończenia. Oznacza to, że w przypadku wielu programów, zamiast samemu sprawdzać wartości wyjściowe, możesz polegać na IPC:: System:: proste do wykonania ciężkiej pracy dla Ciebie:

 use IPC::System::Simple qw(system capture $EXIT_ANY);

 system( [0,1], "frobincate", @files);     # Must return exitval 0 or 1

 my @lines = capture($EXIT_ANY, "baznicate", @files);  # Any exitval is OK.

 foreach my $record (@lines) {
     system( [0, 32], "barnicate", $record);  # Must return exitval 0 or 32
 }

IPC:: System:: Simple jest czystym Perlem, nie ma zależności i działa zarówno na systemach Unix, jak i Windows. Niestety, nie zapewnia sposobu przechwytywania STDERR, więc może nie być odpowiedni dla wszystkich Twoich potrzeb.

IPC:: Run3 zapewnia czysty i łatwy interfejs do ponownego instalowania wszystkich trzech popularnych filehandle, ale niestety nie sprawdza, czy polecenie powiodło się, więc musisz sprawdzić $? ręcznie, co wcale nie jest zabawne. Udostępnienie publicznego interfejsu do kontroli $? czy jest coś co jest na mojej liście zadań dla IPC::System::proste, skoro sprawdzam $? w sposób wieloplatformowy nie jest zadaniem, którego nikomu bym nie życzył.

Istnieją inne moduły w przestrzeni nazw IPC:: , która może również zapewnić Ci pomoc. YMMV.

Wszystkiego najlepszego,

Paweł

 14
Author: pjf,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2008-09-21 00:57:54

Istnieją trzy podstawowe sposoby uruchamiania zewnętrznych poleceń:

system $cmd;        # using system()
$output = `$cmd`;       # using backticks (``)
open (PIPE, "cmd |");   # using open()

Z system(), zarówno STDOUT, jak i STDERR pójdą w to samo miejsce co skrypt STDOUT i STDERR,, chyba że polecenie system() przekieruje je. Backticks i open() odczytują tylko STDOUT Twojego polecenia.

Możesz również wywołać coś podobnego z open, aby przekierować zarówno STDOUT, jak i STDERR.

open(PIPE, "cmd 2>&1 |");

Kod powrotu jest zawsze przechowywany w $?, Jak zauważył @Michael Carman.

 7
Author: hoyhoy,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-05-23 12:17:47

Jeśli robisz się naprawdę skomplikowany, możesz spróbować Expect.pm. ale to prawdopodobnie przesada, jeśli nie musisz również zarządzać wysyłaniem danych wejściowych do procesu.

 0
Author: skiphoppy,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2008-09-21 03:15:38

Uznałem IPC: run3 za bardzo pomocny. Możesz przesłać wszystkie dziecięce rury do glob lub zmiennej; bardzo łatwo! A kod zakończenia będzie przechowywany w $?.

Poniżej, jak chwyciłem stderr, który wiedziałem, że będzie numerem. Cmd wyprowadza transformacje informatyczne na stdout (które przesyłam do pliku w args używając >) i raportuje ile transformacji na STDERR.

use IPC::Run3

my $number;
my $run = run3("cmd arg1 arg2 >output_file",\undef, \undef, \$number);
die "Command failed: $!" unless ($run && $? == 0);
 0
Author: Ian,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2012-04-25 17:21:40