6
votes

utiliser l'opérateur qx {} / `...` de perl avec une liste d'arguments

system , exec , open '| -' , open2 , etc. me permettent tous de spécifier la commande à exécuter comme une liste d'arguments qui seront passés directement à execvp au lieu d'être exécutés via un shell.

Même si perl est assez intelligent pour l'exécuter directement si cela ressemble à une commande "simple", cela m'évite d'avoir à échapper correctement les arguments avec tous les pièges désagréables que cela implique.

Exemple:

sub slurpcmd {
   open my $h, '-|', @_ or die "open $_[0]|: $!";
   local $/ unless wantarray;
   <$h>
}


0 commentaires

3 Réponses :


5
votes

Une forme de liste de l'opérateur qx est fournie par le module IPC :: System: : Simple comme la fonction capturex (en plus comme les autres fonctions de ce module, elle lèvera une exception s'il y a une erreur d'exécution ou un code de réponse non nul, que vous pouvez modifier) . Vous pouvez également utiliser Capture :: Tiny pour envelopper un système principal code> appelle et fournit le même comportement, mais il a aussi d'autres fonctions qui peuvent envelopper STDERR ensemble ou séparément de STDOUT.

use strict;
use warnings;
use IPC::System::Simple 'capturex';
my $output = capturex $prog, @args;

use Capture::Tiny 'capture_stdout';
my ($output, $exit) = capture_stdout { system $prog, @args };
# standard system() error checking required here

Dans le noyau, le tube ouvert est pour la plupart la seule option, à part IPC :: Open3 qui est tout aussi complexe mais permet également de diriger STDERR.


3 commentaires

ces modules ne font pas partie de la distribution standard, non?


@ Căcărău IPC :: System :: Simple et Capture :: Tiny ne sont pas de base, mais ils sont pur-perl donc ils peuvent être fatpacked dans un script.


@zdim Il est fonctionnellement identique à qx, sauf pour la méthode dans laquelle il prend des arguments et sa gestion des erreurs supplémentaire. Cela ne veut pas dire que c'est un autre opérateur intégré, car ce n'est clairement pas le cas.



5
votes

Voici quelques options simples.

  • String :: ShellQuote + qx :

    use IPC::Run qw( run );
    run(\@cmd, \undef, \my $output);
    
  • IPC :: System :: Simple : p>

    use IPC::Run3 qw( run3 );
    run3(\@cmd, \undef, \my $output);
    
  • IPC :: Run3 :

    use IPC::System::Simple qw( capturex );
    my $output = capturex(@cmd)
    
  • IPC :: Run :

    use String::ShellQuote qw( shell_quote );
    my $cmd = shell_quote(@cmd);
    my $output = `$cmd`;
    

La première solution implique un shell, mais aucune des autres.


0 commentaires

1
votes

Il s'avère que (malheureusement) ce n'était pas un oubli de ma part - la seule solution est vraiment de le faire avec open - | ou d'utiliser l'un des modules externes répertoriés dans le autres réponses.

Le backtick l'implémentation (qu'elle soit invoquée par qx /.../ , `...` ou readpipe ) est en profondeur câblé pour accepter un seul argument de chaîne:

PP(pp_backtick)
{
    dSP; dTARGET;
    PerlIO *fp;
    const char * const tmps = POPpconstx;
    const U8 gimme = GIMME_V;
    const char *mode = "r";

    TAINT_PROPER("``");
    if (PL_op->op_private & OPpOPEN_IN_RAW)
        mode = "rb";
    else if (PL_op->op_private & OPpOPEN_IN_CRLF)
        mode = "rt";
    fp = PerlProc_popen(tmps, mode);
    ...

Notez le POPpconstx qui sort un seul argument de la pile et l'utilisation de PerlProc_popen au lieu de PerlProc_popen_list.


1 commentaires

Les commentaires ne sont pas destinés à une discussion approfondie; cette conversation a été déplacé pour chatter . Veuillez modifier la réponse pour incorporer toute information pertinente de la discussion de chat.