Question

Est-il possible d'exécuter un processus externe à partir de Perl, de capturer ses stderr, stdout ET le code de sortie du processus?

Il semble que je sois capable de faire des combinaisons de ceux-ci, par exemple. utilisez backticks pour obtenir stdout, IPC :: Open3 pour capturer les sorties et system () pour obtenir les codes de sortie.

Comment capturez-vous stderr, stdout et le code de sortie en même temps?

Était-ce utile?

La solution

Si vous relisez la documentation pour IPC :: Open3, une note vous invitant à appeler waitpid pour récolter le processus enfant. Une fois cette opération effectuée, le statut devrait être disponible dans $? . La valeur de sortie est $? > > 8 . Voir $? dans perldoc perlvar .

Autres conseils

( Mettre à jour : j'ai mis à jour l'API pour IO :: CaptureOutput afin de rendre cela encore plus facile.)

Il existe plusieurs façons de procéder. Voici une option, en utilisant le module IO :: CaptureOutput :

use IO::CaptureOutput qw/capture_exec/;

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

Il s’agit de la fonction capture_exec (), mais IO :: CaptureOutput a également une fonction plus générale capture () qui peut être utilisée pour capturer la sortie Perl ou la sortie de programmes externes. Donc, si un module Perl utilise un programme externe, vous obtenez toujours le résultat.

Cela signifie également que vous ne devez mémoriser qu'une seule approche pour capturer STDOUT et STDERR (ou les fusionner) au lieu d'utiliser IPC :: Open3 pour les programmes externes et d'autres modules de capture de la sortie Perl.

Si vous ne voulez pas le contenu de STDERR, la commande capture () de IPC :: System :: Simple est presque exactement ce que vous recherchez:

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

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

   my $exit_value = $EXITVAL;

Vous pouvez utiliser capture () avec un seul argument pour appeler le shell ou plusieurs arguments pour éviter le shell de manière fiable. Il y a aussi capturex () qui n'appelle jamais le shell, même avec un seul argument.

Contrairement aux commandes système et backticks intégrées de Perl, IPC :: System :: Simple renvoie la valeur de sortie 32 bits complète sous Windows. Il lève également une exception détaillée si la commande ne peut pas être démarrée, meurt à un signal ou renvoie une valeur de sortie inattendue. Cela signifie que pour de nombreux programmes, vous pouvez compter sur IPC :: System :: Simple pour faire le travail dur pour vous:

 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 est un pur Perl, il n’a pas de dépendances et fonctionne sur les systèmes Unix et Windows. Malheureusement, cela ne permet pas de capturer STDERR, il est donc possible qu’il ne convienne pas à tous vos besoins.

IPC :: Run3 fournit une interface claire et simple pour replacer tout le contenu. trois descripteurs de fichiers courants, mais malheureusement, il ne vérifie pas si la commande a réussi, vous devez donc inspecter $? manuellement, ce qui n'est pas du tout amusant. Fournir une interface publique pour inspecter $? est-ce quelque chose qui figure sur ma liste de tâches pour IPC: : System :: Simple, depuis l'inspection de $? sur une plate-forme multiplateforme n’est pas une tâche que j’aimerais souhaiter à quiconque.

Le espace de noms IPC :: contient d'autres modules. cela peut aussi vous aider. YMMV.

Tout le meilleur,

Paul

Il existe trois méthodes de base pour exécuter des commandes externes:

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

Avec system () , STDOUT et STDERR iront au même endroit que le STDOUT et le STDERR du script, sauf si la commande system () les redirige. Les Backticks et open () ne lisent que le STDOUT de votre commande.

Vous pouvez également appeler le code suivant avec open pour rediriger STDOUT et STDERR .

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

Le code de retour est toujours stocké dans $? , comme indiqué par @Michael Carman .

Si vous devenez vraiment compliqué, essayez Expect.pm. Mais c’est probablement exagéré si vous n’avez pas besoin de gérer également l’envoi de données au processus.

J'ai trouvé IPC: run3 . être très utile. Vous pouvez transférer tous les canaux enfants vers un glob ou une variable. très facilement! Et le code de sortie sera stocké dans $ ?.

Ci-dessous, voici comment j’ai attrapé stderr et je savais que ce serait un numéro. La cmd a généré des transformations informatiques en sortie standard (qui ont été transférées vers un fichier dans les arguments en utilisant >) et ont indiqué combien de transformations en STDERR.

use IPC::Run3

my $number;
my $run = run3("cmd arg1 arg2 >output_file",\undef, \undef, \$number);
die "Command failed: $!" unless ($run && $? == 0);
Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top