Quelle est la différence entre les backticks, le système et l'exec de Perl?

237

Quelqu'un peut-il m'aider? En Perl, quelle est la différence entre:

exec "command";

et

system("command");

et

print `command`;

Existe-t-il également d'autres façons d'exécuter des commandes shell?

rlbond
la source
8
Presque un double exact de stackoverflow.com/questions/797127/… , sauf que celui-ci a un exécutable et l'autre a des tuyaux.
Michael Myers

Réponses:

268

exec

exécute une commande et ne revient jamais . C'est comme une returndéclaration dans une fonction.

Si la commande n'est pas trouvée, execrenvoie false. Il ne retourne jamais vrai, car si la commande est trouvée, elle ne revient jamais du tout. Il est également inutile de revenir STDOUT, STDERRou de l' état de sortie de la commande. Vous pouvez trouver de la documentation à ce sujet dans perlfunc, car il s'agit d'une fonction.

système

exécute une commande et votre script Perl se poursuit une fois la commande terminée.

La valeur de retour est l'état de sortie de la commande. Vous pouvez trouver de la documentation à ce sujet dans perlfunc.

astuces

comme systemexécute une commande et votre script perl se poursuit une fois la commande terminée.

Contrairement à systemla valeur de retour est STDOUTde la commande. qx//équivaut à des backticks. Vous pouvez trouver de la documentation à ce sujet dans perlop, car contrairement à systemet execc'est un opérateur.


D'autres moyens

Ce qui manque dans ce qui précède est un moyen d'exécuter une commande de manière asynchrone. Cela signifie que votre script perl et votre commande s'exécutent simultanément. Cela peut être accompli avec open. Il vous permet de lire STDOUT/ STDERRécrire sur STDINvotre commande. Cela dépend de la plateforme.

Il existe également plusieurs modules qui peuvent faciliter ces tâches. Il y a IPC::Open2et IPC::Open3et IPC::Run, ainsi que Win32::Process::Createsi vous êtes sous Windows.

Ludwig Weinzierl
la source
1
Je pense que vous voulez dire s / perlcunc / perlfunc / ... aussi la documentation perlipc va en profondeur sur l'ouverture des tuyaux.
éphémère
7
perlcunc, peut-être que ce sera mon nouveau surnom ;-)
Ludwig Weinzierl
8
Pour mémoire, les backticks et qx [] remplissent également $? (la valeur de retour du système d'exploitation).
jjohn
167

En usage général I system, open, IPC::Open2ou en IPC::Open3fonction de ce que je veux faire. L' qx//opérateur, bien que simple, est trop contraignant dans sa fonctionnalité pour être très utile en dehors des hacks rapides. Je trouve openbeaucoup plus pratique.

system: exécutez une commande et attendez qu'elle revienne

À utiliser systemlorsque vous souhaitez exécuter une commande, ne vous souciez pas de sa sortie et ne voulez pas que le script Perl fasse quoi que ce soit jusqu'à la fin de la commande.

#doesn't spawn a shell, arguments are passed as they are
system("command", "arg1", "arg2", "arg3");

ou

#spawns a shell, arguments are interpreted by the shell, use only if you
#want the shell to do globbing (e.g. *.txt) for you or you want to redirect
#output
system("command arg1 arg2 arg3");

qx//ou `` : exécutez une commande et capturez son STDOUT

À utiliser qx//lorsque vous souhaitez exécuter une commande, capturer ce qu'elle écrit dans STDOUT et ne souhaitez pas que le script Perl fasse quoi que ce soit tant que la commande n'est pas terminée.

#arguments are always processed by the shell

#in list context it returns the output as a list of lines
my @lines = qx/command arg1 arg2 arg3/;

#in scalar context it returns the output as one string
my $output = qx/command arg1 arg2 arg3/;

exec: remplace le processus actuel par un autre processus.

À utiliser execavec forklorsque vous souhaitez exécuter une commande, ne vous souciez pas de sa sortie et ne voulez pas attendre qu'elle revienne. systemest vraiment juste

sub my_system {
    die "could not fork\n" unless defined(my $pid = fork);
    return waitpid $pid, 0 if $pid; #parent waits for child
    exec @_; #replace child with new process
}

Vous pouvez également lire les manuels waitpidet perlipc.

open: exécuter un processus et créer un canal vers son STDIN ou STDERR

À utiliser openlorsque vous souhaitez écrire des données dans le STDIN d'un processus ou lire des données dans le STDOUT d'un processus (mais pas les deux en même temps).

#read from a gzip file as if it were a normal file
open my $read_fh, "-|", "gzip", "-d", $filename
    or die "could not open $filename: $!";

#write to a gzip compressed file as if were a normal file
open my $write_fh, "|-", "gzip", $filename
    or die "could not open $filename: $!";

IPC :: Open2 : exécutez un processus et créez un canal vers STDIN et STDOUT

À utiliser IPC::Open2lorsque vous devez lire et écrire dans les STDIN et STDOUT d'un processus.

use IPC::Open2;

open2 my $out, my $in, "/usr/bin/bc"
    or die "could not run bc";

print $in "5+6\n";

my $answer = <$out>;

IPC :: Open3 : exécutez un processus et créez un canal vers STDIN, STDOUT et STDERR

à utiliser IPC::Open3lorsque vous devez capturer les trois descripteurs de fichiers standard du processus. J'écrirais un exemple, mais cela fonctionne principalement de la même manière que IPC :: Open2, mais avec un ordre légèrement différent des arguments et un troisième descripteur de fichier.

Chas. Owens
la source
Réponse très informative et à jour. Merci @ chas-owens
Jassi
IPC :: Open3 est trop bas pour la plupart des utilisations. IPC :: Run3 et IPC :: Run sont généralement beaucoup plus appropriés.
ikegami
17

Permettez-moi de citer d'abord les manuels:

perldoc exec () :

La fonction exec exécute une commande système et ne revient jamais - utilisez system au lieu de exec si vous voulez qu'elle revienne

système perldoc () :

Fait exactement la même chose que exec LIST, sauf qu'un fork est fait en premier et que le processus parent attend la fin du processus enfant.

Contrairement à exec et system , les backticks ne vous donnent pas la valeur de retour mais le STDOUT collecté.

perldoc `String` :

Une chaîne qui est (éventuellement) interpolée puis exécutée en tant que commande système avec / bin / sh ou son équivalent. Les caractères génériques, les tuyaux et les redirections de Shell seront honorés. La sortie standard collectée de la commande est renvoyée ; l'erreur standard n'est pas affectée.


Alternatives:

Dans des scénarios plus complexes, où vous souhaitez récupérer STDOUT, STDERR ou le code retour, vous pouvez utiliser des modules standard bien connus comme IPC :: Open2 et IPC :: Open3 .

Exemple:

use IPC::Open2;
my $pid = open2(\*CHLD_OUT, \*CHLD_IN, 'some', 'cmd', 'and', 'args');
waitpid( $pid, 0 );
my $child_exit_status = $? >> 8;

Enfin, IPC :: Run from the CPAN mérite également d'être examiné…

Benedikt Waldvogel
la source
3
Ceci est une réponse grossière. Vous devriez essayer d'être utile sans colère.
Shane C. Mason
1
Je pense qu'il faisait simplement référence à l'ol 'RTFM: P
v3.
n'était pas censé être grossier en fait;) a cependant supprimé le mot f, pour éviter tout malentendu…
Benedikt Waldvogel
2
Je ne l'ai certainement pas interprété comme étant impoli. Brusque, peut-être, mais ce n'est pas une question très intelligente nécessitant une réponse réfléchie.
éphémère le
11

Quelle est la différence entre les backticks de Perl ( `) system, et exec?

exec -> exec "command"; ,
system -> system("command"); and 
backticks -> print `command`;

exec

execexécute une commande et ne reprend jamais le script Perl. C'est à un script comme une returndéclaration est à une fonction.

Si la commande n'est pas trouvée, execrenvoie false. Il ne retourne jamais vrai, car si la commande est trouvée, elle ne revient jamais du tout. Il est également inutile de revenir STDOUT,STDERR ou de l' état de sortie de la commande. Vous pouvez trouver de la documentation à ce sujet dans perlfunc , car il s'agit d'une fonction.

Par exemple:

#!/usr/bin/perl
print "Need to start exec command";
my $data2 = exec('ls');
print "Now END exec command";
print "Hello $data2\n\n";

Dans le code ci-dessus, il y a trois print instructions, mais en raison de la execsortie du script, seule la première instruction print est exécutée. De plus, la execsortie de la commande n'est affectée à aucune variable.

Ici, vous n'obtenez que la sortie de la première printinstruction et de l'exécution de la lscommande en sortie standard.

system

systemexécute une commande et votre script Perl reprend une fois la commande terminée. La valeur de retour est l'état de sortie de la commande. Vous pouvez trouver de la documentation à ce sujet dans perlfunc .

Par exemple:

#!/usr/bin/perl
print "Need to start system command";
my $data2 = system('ls');
print "Now END system command";
print "Hello $data2\n\n";

Dans le code ci-dessus, il y a trois print instructions. Lorsque le script reprend après la systemcommande, les trois instructions d'impression sont exécutées.

En outre, le résultat de l'exécution system est affecté à data2, mais la valeur affectée est0 (le code de sortie de ls).

Ici, vous obtenez la sortie de la première printinstruction, puis celle de la lscommande, suivie des sorties des deux dernières printinstructions sur la sortie standard.

backticks ( `)

Par exemple system, placer une commande entre guillemets exécute cette commande et votre script Perl est repris une fois la commande terminée. Contrairement à system, la valeur de retour est STDOUTde la commande. qx//équivaut à des backticks. Vous pouvez trouver de la documentation à ce sujet dans perlop , car contrairement au système et exec, c'est un opérateur.

Par exemple:

#!/usr/bin/perl
print "Need to start backticks command";
my $data2 = `ls`;
print "Now END system command";
print "Hello $data2\n\n";

Dans le code ci-dessus, il y a trois printinstructions et les trois sont en cours d'exécution. La sortie de lsne va pas être standardisée directement, mais affectée à la variable data2, puis imprimée par l'instruction d'impression finale.

linuxtestside
la source
Meilleure explication avec exemple. Merci beaucoup.
Arslan Anwar
2

La différence entre 'exec' et 'system' est que exec remplace votre programme actuel par 'command' et ne revient JAMAIS à votre programme. système, d'autre part, bifurque et exécute 'commande' et vous renvoie l'état de sortie de 'commande' lorsqu'il est terminé. La coche arrière exécute «commande», puis retourne une chaîne représentant sa sortie standard (quelle qu'elle soit imprimée à l'écran)

Vous pouvez également utiliser popen pour exécuter des commandes shell et je pense qu'il existe un module shell - «utiliser shell» qui vous donne un accès transparent aux commandes shell typiques.

J'espère que cela vous le clarifie.

Shane C. Mason
la source
Peut-être voulez-vous dire use Shell;( search.cpan.org/dist/Shell/Shell.pm )? Il n'est pas largement installé, et il n'est pas applicable à la question, je pense ...
éphémère
1
La dernière partie de sa question était "y a-t-il d'autres façons d'exécuter des commandes shell aussi" - Shell est une autre façon d'exécuter des commandes shell.
Shane C. Mason
2
Les documents indiquent spécifiquement "Ce package est inclus en tant que vitrine, illustrant quelques fonctionnalités de Perl. Il ne doit pas être utilisé pour les programmes de production. Bien qu'il fournisse une interface simple pour obtenir la sortie standard de commandes arbitraires, il peut y avoir mieux façons d'atteindre ce dont vous avez besoin. "
Chas. Owens
2
Encore une fois, il a répondu à sa question «y a-t-il d'autres façons»
Shane C. Mason
Les moyens incorrects et non pris en charge ne doivent pas être indiqués sans avertir qu'ils sont mauvais et non pris en charge.
Chas. Owens