it-swarm-eu.dev

Jak se vám zachytit stderr, stdout, a výstupní kód najednou, v Perlu?

Je možné spustit externí proces z Perlu, zachytit jeho stderr, stdout a výstupní kód procesu?

Zdá se, že jsem schopen tyto kombinace provádět, např. použití backticks dostat stdout, IPC :: Open3 k zachycení výstupů, a systém () získat výstupní kódy.

Jak zachytíte stderr, stdout a výstupní kód najednou?

56
Scooby

Pokud si znovu přečtete dokumentaci pro IPC :: Open3, uvidíte poznámku, že byste měli zavolat waitpid a sklidit proces dítěte. Jakmile toto provedete, stav by měl být k dispozici v souboru $?. Výstupní hodnota je $? >> 8. Viz $? v perldoc perlvar .

26
Michael Carman

(Update: Aktualizoval jsem rozhraní API pro IO :: CaptureOutput, aby to bylo ještě snazší.)

Existuje několik způsobů, jak toho dosáhnout. Zde je jedna možnost, pomocí modulu IO :: CaptureOutput :

use IO::CaptureOutput qw/capture_exec/;

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

Toto je funkce capture_exec (), ale IO :: CaptureOutput má také obecnější funkci capture (), kterou lze použít k zachycení výstupu Perlu nebo výstupu z externích programů. Pokud tedy některý modul Perlu používá nějaký externí program, stále máte výstup.

Znamená to také, že si musíte pamatovat pouze jeden přístup k zachycení STDOUT a STDERR (nebo jejich sloučení) namísto použití IPC :: Open3 pro externí programy a další moduly pro zachycení výstupu Perlu.

41
xdg

Pokud nechcete obsah STDERR, pak příkaz capture () z IPC :: System :: Simple module je téměř přesně to, po čem jste:

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

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

   my $exit_value = $EXITVAL;

Můžete použít capture () s jedním argumentem k vyvolání Shell, nebo více argumentů, aby se Shell spolehlivě vyhnul. K dispozici je také capturex (), který nikdy neříká Shell, dokonce ani s jedním argumentem.

Na rozdíl od vestavěných systémových a backtick příkazů v Perlu, IPC :: System :: Simple vrací v systému Windows plnou 32bitovou výstupní hodnotu. Také vyvolá podrobnou výjimku, pokud příkaz nelze spustit, zemře na signál nebo vrátí neočekávanou výstupní hodnotu. To znamená, že pro mnoho programů, místo kontroly výstupních hodnot sami, se můžete spolehnout na IPC :: System :: Jednoduchá práce pro vás:

 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 je čistý Perl, nemá žádné závislosti a pracuje na systémech Unix i Windows. Bohužel to neposkytuje způsob, jak zachytit STDERR, takže nemusí být vhodný pro všechny vaše potřeby.

IPC :: Run3 poskytuje čisté a snadné rozhraní do re-plumbing všechny tři společné filehandles, ale bohužel to nekontroluje, zda příkaz byl úspěšný, takže budete muset prohlédnout $? ručně, což není vůbec zábavné. Poskytování veřejného rozhraní pro kontrolu $? je něco, co je na mém seznamu úkolů pro IPC :: System :: Simple, protože kontroluje $? v multiplatformní módě není úkolem, který bych si přál.

Existují i ​​další moduly v oboru názvů IPC :: , které vám také mohou poskytnout pomoc. YMMV.

Vše nejlepší,

Pavel

14
pjf

Existují tři základní způsoby spouštění externích příkazů:

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

S system(), oba STDOUT a STDERR půjdou na stejné místo jako STDOUT a STDERR, skriptu, pokud je příkaz system() přesměruje. Backticks a open() číst pouze STDOUT vašeho příkazu.

Můžete také zavolat něco podobného s otevřeným přesměrováním jak STDOUT, tak STDERR

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

Návratový kód je vždy uložen v souboru $?, jak poznamenal @ Michael Carman .

7
hoyhoy

Pokud jste opravdu složité, můžete zkusit Expect.pm. Ale to je pravděpodobně přehnané, pokud nemusíte také spravovat odesílání vstupů do procesu.

0
skiphoppy

Našel jsem IPC: run3 aby bylo velmi užitečné. Můžete předat všechna podřízená potrubí globální nebo proměnné; velmi lehce! Kód výstupu bude uložen v $ ?.

Níže je, jak jsem chytil stderr, který jsem věděl, že by bylo číslo. Výstupem cmd jsou informativní transformace na stdout (které jsem do souboru v argách zavěsil pomocí>) a nahlásil, kolik transformací 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
Ian