eval
et exec
sont tous deux des commandes intégrées de bash (1) qui exécutent des commandes.
Je vois aussi exec
quelques options mais est-ce la seule différence? Qu'advient-il de leur contexte?
bash
shell
shell-builtin
Willian Paixao
la source
la source
Réponses:
eval
etexec
sont des bêtes complètement différentes. (Mis à part le fait que les deux exécuteront des commandes, tout comme tout ce que vous faites dans un shell.)Ce
exec cmd
qui est identique à l’exécutioncmd
, à la différence que le shell actuel est remplacé par la commande, au lieu d’un processus séparé en cours d’exécution. En interne, par exemple en cours d' exécution/bin/ls
fera appelfork()
pour créer un processus enfant, puisexec()
chez l'enfant à exécuter/bin/ls
.exec /bin/ls
d'autre part ne sera pas fourche, mais remplace simplement la coquille.Comparer:
avec
echo $$
affiche le PID du shell que j'ai commencé et la liste/proc/self
nous donne le PID duls
shell exécuté. En règle générale, les ID de processus sont différents, mais avecexec
le shell etls
ont le même ID de processus. De plus, la commande suivanteexec
n'a pas été exécutée, car le shell a été remplacé.D'autre part:
eval
exécutera les arguments en tant que commande dans le shell actuel. En d'autres termes,eval foo bar
c'est la même chose que justefoo bar
. Mais les variables seront développées avant l'exécution, nous pouvons donc exécuter des commandes sauvegardées dans des variables shell:Il ne créera pas de processus enfant, la variable est donc définie dans le shell actuel. (Bien sûr,
eval /bin/ls
cela créera un processus enfant, comme le/bin/ls
ferait un vieux vieux .)Ou nous pourrions avoir une commande qui génère des commandes shell. En cours d'exécution,
ssh-agent
l'agent démarre en arrière-plan et génère un ensemble d'affectations de variables, qui peuvent être définies dans le shell actuel et utilisées par les processus enfants (lesssh
commandes que vous exécutez). Par conséquent,ssh-agent
peut être démarré avec:Et le shell actuel obtiendra les variables pour que les autres commandes héritent.
Bien sûr, si la variable
cmd
contenait quelque chose commerm -rf $HOME
, alors courireval "$cmd"
ne serait pas quelque chose que vous voudriez faire. Même les choses comme les substitutions de commandes à l' intérieur de la chaîne seraient traitées, donc il faut vraiment être sûr que l'entréeeval
est en sécurité avant de l' utiliser.Souvent, il est possible d'éviter
eval
et d'éviter, même accidentellement, le mélange du code et des données de manière incorrecte.la source
eval
en premier lieu . Des choses comme modifier indirectement des variables peuvent être faites dans beaucoup de shells viadeclare
/typeset
/nameref
et des extensions comme${!var}
, alors je les utiliserais plutôteval
que si je devais vraiment l'éviter.exec
ne crée pas de nouveau processus. Il remplace le processus en cours par la nouvelle commande. Si vous avez fait cela sur la ligne de commande, cela mettra fin à votre session shell (et peut-être vous déconnecter ou fermer la fenêtre du terminal!)par exemple
Ici je suis dedans
ksh
(ma coquille normale). Je commencebash
et puis bash jeexec /bin/echo
. Nous pouvons voir que je suis retombéksh
après parce que lebash
processus a été remplacé par/bin/echo
.la source
TL; DR
exec
est utilisé pour remplacer le processus shell actuel par de nouveaux descripteurs de fichier et de gestion de redirection de flux / fichier si aucune commande n'a été spécifiée.eval
est utilisé pour évaluer les chaînes en tant que commandes. Les deux peuvent être utilisés pour construire et exécuter une commande avec des arguments connus au moment de l'exécution, maisexec
remplace le processus du shell actuel en plus de l'exécution des commandes.exec buil-in
Syntaxe:
Selon le manuel, si une commande est spécifiée, cette commande intégrée
En d'autres termes, si vous utilisiez le
bash
PID 1234 et si vous deviez l'exécuterexec top -u root
dans ce shell, latop
commande contiendrait alors le PID 1234 et remplacerait votre processus de shell.Où est-ce utile? Dans quelque chose connu sous le nom de scripts wrapper. Ces scripts construisent des ensembles d'arguments ou prennent certaines décisions quant aux variables à transmettre à l'environnement, puis sont utilisés
exec
pour se remplacer par la commande spécifiée, en fournissant bien sûr les mêmes arguments que le script d'encapsuleur.Le manuel indique également que:
Cela nous permet de rediriger n'importe quoi des flux de sortie des shells actuels dans un fichier. Cela peut être utile pour la journalisation ou le filtrage, où vous ne voulez pas voir les
stdout
commandes mais seulementstderr
. Par exemple, comme ceci:Ce comportement le rend pratique pour la journalisation dans des scripts de shell , la redirection de flux vers des fichiers ou processus distincts et d'autres tâches amusantes avec des descripteurs de fichiers.
Au niveau du code source au moins pour la
bash
version 4.3, leexec
composant intégré est défini dansbuiltins/exec.def
. Il analyse les commandes reçues et, s’il y en a, il transmet les informations à lashell_execve()
fonction définie dans leexecute_cmd.c
fichier.En résumé, il existe une famille de
exec
commandes en langage de programmation C, quishell_execve()
est en fait une fonction wrapper deexecve
:eval intégré
Le manuel de bash 4.3 déclare (soulignement ajouté par moi):
Notez qu'il n'y a pas de remplacement de processus en cours. Contrairement aux
exec
cas où l'objectif est de simuler desexecve()
fonctionnalités, la fonctioneval
intégrée ne sert qu'à "évaluer" les arguments, comme si l'utilisateur les avait saisis sur la ligne de commande. En tant que tels, de nouveaux processus sont créés.Où cela pourrait être utile? Comme Gilles l'a souligné dans sa réponse , "... eval n'est pas utilisé très souvent. Dans certains shells, l'utilisation la plus courante consiste à obtenir la valeur d'une variable dont le nom n'est connu qu'au moment de l'exécution". Personnellement, je l'ai utilisé dans quelques scripts sur Ubuntu où il était nécessaire d'exécuter / évaluer une commande en fonction de l'espace de travail spécifique que l'utilisateur utilisait actuellement.
Au niveau du code source, il est défini dans
builtins/eval.def
et transmet la chaîne d'entrée analysée àevalstring()
function.Entre autres choses, vous
eval
pouvez affecter des variables qui restent dans l’environnement d’exécution actuel du shell, alors queexec
vous ne pouvez pas:la source
Euh quoi? Le problème
eval
est que cela ne crée en aucun cas un processus enfant. Si je faisdans un shell, le shell actuel aura ensuite changé de répertoire. Il ne
exec
crée pas non plus de nouveau processus enfant, mais change l’exécutable en cours (à savoir le shell) pour celui qui est donné. L'identifiant du processus (et les fichiers ouverts, etc.) reste identique. Par opposition àeval
, anexec
ne retournera pas au shell appelant à moins que leexec
client échoue en raison de son incapacité à trouver ou à charger l'exécutable ou à résoudre les problèmes de développement d'arguments.eval
interprète fondamentalement ses arguments comme une chaîne après la concaténation, c’est-à-dire qu’il crée une couche supplémentaire d’expansion de caractères génériques et de fractionnement d’arguments.exec
ne fait rien comme ça.la source
Évaluation
Ces fonctionnent:
Cependant, ceux-ci ne:
Process image de remplacement
Cet exemple montre comment
exec
remplace l'image de son processus appelant:Avis qui a
exec echo $$
fonctionné avec le PID du sous-shell! De plus, une fois terminé, nous sommes revenus dans notresh$
coquille d' origine .Par contre,
eval
ne remplace pas l’image process. Au lieu de cela, il exécute la commande donnée comme vous le feriez normalement dans le shell lui-même. (Bien sûr, si vous exécutez une commande nécessitant un processus, elle le fait!)la source
exec
)