Je lisais un script bash que quelqu'un a fait et j'ai remarqué que l'auteur n'utilisait pas eval pour évaluer une variable en tant que commande
L'auteur a utilisé
bash -c "$1"
au lieu de
eval "$1"
Je suppose que l’utilisation de eval est la méthode préférée et que c’est probablement plus rapide de toute façon. Est-ce vrai?
Y a-t-il une différence pratique entre les deux? Quelles sont les différences notables entre les deux?
bash
shell-script
bash-script
qui suis je
la source
la source
e='echo foo'; $e
fonctionne très bien.Réponses:
eval "$1"
exécute la commande dans le script en cours. Il peut définir et utiliser des variables shell à partir du script en cours, des variables d'environnement pour le script en cours, définir et utiliser des fonctions à partir du script en cours, définir le répertoire en cours, umask, les limites et autres attributs du script en cours, etc.bash -c "$1"
exécute la commande dans un script complètement séparé, qui hérite des variables d'environnement, des descripteurs de fichier et de tout autre environnement de processus (mais ne renvoie aucune modification) mais n'hérite pas des paramètres de shell internes (variables d'environnement, fonctions, options, interruptions, etc.).Il existe un autre moyen,
(eval "$1")
qui exécute la commande dans un sous-shell: il hérite de tout du script appelant mais ne renvoie aucune modification.Par exemple, en supposant que la variable
dir
n'est pas exportée et$1
estcd "$foo"; ls
, alors:cd /starting/directory; foo=/somewhere/else; eval "$1"; pwd
liste le contenu/somewhere/else
et les impressions/somewhere/else
.cd /starting/directory; foo=/somewhere/else; (eval "$1"); pwd
liste le contenu/somewhere/else
et les impressions/starting/directory
.cd /starting/directory; foo=/somewhere/else; bash -c "$1"; pwd
répertorie le contenu de/starting/directory
(carcd ""
ne change pas le répertoire en cours) et imprime/starting/directory
.la source
(eval "$1")
n'a rien à voir avecsource
. C'est juste une combinaison de(…)
eteval
.source foo
est à peu près équivalent àeval "$(cat foo)"
.eval
et.dot
est queeval
fonctionne avec des arguments et.dot
avec des fichiers.La différence la plus importante entre
Et
Est-ce que le premier fonctionne dans un sous-shell et le second ne le fait pas. Alors:
SORTIE:
SORTIE:
Je ne sais pas pourquoi quelqu'un utiliserait jamais l'exécutable
bash
de cette manière, cependant. Si vous devez l’appeler, utilisez l’intégration garantie POSIXsh
. Ou(subshell eval)
si vous souhaitez protéger votre environnement.Personnellement, je préfère la coquille
.dot
avant tout.SORTIE
Mais en avez-vous besoin?
En réalité, la seule cause à utiliser est le cas où votre variable en attribue ou en évalue une autre, ou le fractionnement des mots est important pour la sortie.
Par exemple:
SORTIE:
Cela fonctionne, mais seulement parce
echo
que peu importe le nombre d'arguments.SORTIE:
Voir? Les doubles guillemets arrivent car le résultat de l'expansion du shell de
$var
n'est pas évaluéquote-removal
.SORTIE:
Mais avec
eval
oush
:SORTIE:
Lorsque nous utilisons
eval
ou quesh
le shell passe en revue les résultats des extensions et les évalue également comme une commande potentielle, les guillemets font une différence. Vous pouvez aussi faire:SORTIE
la source
J'ai fait un test rapide:
(Oui, je sais, j'ai utilisé bash -c pour exécuter la boucle mais cela ne devrait pas faire la différence).
Les resultats:
Alors
eval
c'est plus rapide. De la page de manuel deeval
:bash -c
bien sûr, exécute la commande dans un shell bash. Une note: j'ai utilisé/bin/echo
parce queecho
c'est un shell intégrébash
, ce qui signifie qu'un nouveau processus n'a pas besoin d'être démarré. En remplaçant/bin/echo
parecho
pour lebash -c
test, cela a pris1.28s
. C'est à peu près la même chose. Cependant,eval
est plus rapide pour exécuter des exécutables. La différence clé ici est queeval
ne démarre pas un nouveau shell (il exécute la commande dans celui en cours), tandis quebash -c
démarre un nouveau shell, puis exécute la commande dans le nouveau shell. Démarrer un nouveau shell prend du temps, c'est pourquoi ilbash -c
est plus lent queeval
.la source
bash -c
aveceval
pasexec
.bash -c
n'est pas si mal ...