Qu'est-ce que la commande "eval" dans bash?


177

Que pouvez-vous faire avec la evalcommande? Pourquoi est-ce utile? Est-ce une sorte de fonction intégrée dans bash? Il n'y a pas de manpage pour cela ..


28
Utilisez type commandpour savoir de quel type est une commande . ( type evaldans ce cas)
rozcietrzewiacz

9
"eval est un shell construit"
Nuno Rafael Figueiredo

3
help evalobtenir la page "man" de votre shell
m-ric

eval est intégré à bash et est documenté dans la page de manuel de bash. Il suffit donc de taper "man bash" et de rechercher la section appropriée pour eval. Ceci s’applique également aux autres commandes intégrées de bash.
Dirk Thannhäuser

Réponses:


132

evalfait partie de POSIX. C'est une interface qui peut être un shell intégré.

Son décrit dans le "Manuel du programmeur POSIX": http://www.unix.com/man-page/posix/1posix/eval/

eval - construct command by concatenating arguments

Il faudra un argument et en construit une commande, qui sera exécutée par le shell. Voici l'exemple de la page de manuel:

1) foo=10 x=foo
2) y='$'$x
3) echo $y
4) $foo
5) eval y='$'$x
6) echo $y
7) 10
  1. Dans la première ligne, vous définissez $fooavec la valeur '10'et $xavec la valeur 'foo'.
  2. Définissez maintenant $y, qui consiste en la chaîne '$foo'. Le signe dollar doit être échappé avec '$'.
  3. Pour vérifier le résultat, echo $y.
  4. Le résultat sera la chaîne '$foo'
  5. Maintenant, nous répétons la mission avec eval. Il va d'abord évaluer $xà la chaîne 'foo'. Nous avons maintenant la déclaration y=$fooqui sera évaluée y=10.
  6. Le résultat de echo $yest maintenant la valeur '10'.

C'est une fonction courante dans de nombreuses langues, par exemple Perl et JavaScript. Consultez perldoc eval pour plus d'exemples: http://perldoc.perl.org/functions/eval.html


4
Dans la terminologie du shell, evalest une fonction intégrée, pas une fonction. En pratique, les fonctions intégrées se comportent beaucoup comme des fonctions qui n'ont pas de définition dans le langage, mais pas tout à fait (comme cela apparaît si vous êtes assez tordu pour définir une fonction appelée eval).
Gilles

merci, corrigé que :-)
echox

4
Quelle est la difference entre eval et backticks `?
JohnyTex

5
Les backticks sont un raccourci pour l'exécution d'un autre shell entier, ce qui signifie que vous aurez un autre processus enfant bash / sh en cours d'exécution dans votre script.
Aaron R.

Pourquoi echo $ y (stage 3) ramène foo (10) au lieu de $ foo? (c'est-à-dire juste la valeur de foo au lieu de la chaîne $ + la valeur de foo)?
JohnDoea

60

Oui, evalest une commande interne bash, elle est donc décrite dans la bashpage de manuel.

eval [arg ...]
    The  args  are read and concatenated together into a single com-
    mand.  This command is then read and executed by the shell,  and
    its  exit status is returned as the value of eval.  If there are
    no args, or only null arguments, eval returns 0.

Il est généralement utilisé en combinaison avec une substitution de commande . Sans explicite eval, le shell tente d' exécuter le résultat d'une substitution de commande et non de l' évaluer .

Dites que vous voulez coder un équivalent de VAR=value; echo $VAR. Notez la différence dans la façon dont le shell traite les écrits de echo VAR=value:

  1. andcoz@...:~> $( echo VAR=value )
    bash: VAR=value: command not found
    andcoz@...:~> echo $VAR
    <empty line>
    

    Le shell tente de s’exécuter echoet VAR=valuesous forme de deux commandes distinctes. Cela renvoie une erreur à propos de la deuxième chaîne. La mission reste inefficace.

  2. andcoz@...:~> eval $( echo VAR=value )
    andcoz@...:~> echo $VAR
    value
    
    Le shell fusionne (concatène) les deux chaînes echoet VAR=valueanalyse cette unité en fonction de règles appropriées et l'exécute.

Last but not least, evalpeut être une commande très dangereuse. Toute entrée dans une evalcommande doit être soigneusement vérifiée pour éviter les problèmes de sécurité.


18

evaln'a pas de page de manuel car ce n'est pas une commande externe séparée, mais plutôt un shell intégré, c'est-à-dire une commande interne à et connue uniquement du shell ( bash). La partie pertinente de la bashpage de manuel dit:

eval [arg ...]
    The args are read and concatenated together into a single command.  
    This command is then  read  and executed by the shell, and its exit 
    status is returned as the value of eval.  If there are no args, or only 
    null arguments, eval returns 0

De plus, la sortie if help evalest:

eval: eval [arg ...]
    Execute arguments as a shell command.

    Combine ARGs into a single string, use the result as input to the shell,
    and execute the resulting commands.

    Exit Status:
    Returns exit status of command or success if command is null.

evalC’est une commande puissante et si vous avez l’intention de l’utiliser, vous devez faire très attention à ne pas risquer de compromettre la sécurité .


16

L'instruction eval indique au shell de prendre les arguments de eval en tant que commande et de les exécuter via la ligne de commande. C'est utile dans une situation comme celle ci-dessous:

Dans votre script, si vous définissez une commande dans une variable et que vous souhaitez utiliser cette commande ultérieurement, vous devez utiliser eval:

/home/user1 > a="ls | more"
/home/user1 > $a
bash: command not found: ls | more
/home/user1 > # Above command didn't work as ls tried to list file with name pipe (|) and more. But these files are not there
/home/user1 > eval $a
file.txt
mailids
remote_cmd.sh
sample.txt
tmp
/home/user1 >

3
Le commentaire de la ligne 4 de votre exemple est incorrect: "La commande ci-dessus n'a pas fonctionné car bash a tenté de trouver une commande appelée ls | more. En d'autres termes, le nom de la commande unique était composé de neuf caractères, espaces et symbole de tuyau compris. .
tpi

J'ai exactement le même comportement qu'il a rapporté. bash --version == GNU bash, version 3.2.57 (1) -release (x86_64-apple-darwin18)
Alexander Bird

10

Eval c'est quoi?

eval est une commande shell généralement implémentée.

Dans POSIX, il est répertorié dans "2.14. Utilitaires intégrés spéciaux" à l’entrée "eval" .
Ce qui est construit signifie:

Le terme "intégré" implique que le shell peut exécuter l'utilitaire directement et n'a pas besoin de le rechercher.

Qu'est ce que ça fait?

En termes simples: crée une ligne d’entrée à analyser deux fois .

Comment ça fait ça?

Le shell a une séquence d'étapes à suivre pour "traiter" une ligne. Vous pouvez regarder cette image et vous rendre compte que eval est la seule ligne qui monte vers la première étape, à gauche. De la description POSIX :

2.1 Introduction de Shell

  1. Le shell lit son entrée ....
  2. Le shell décompose l'entrée en jetons: mots et opérateurs
  3. Le shell analyse les entrées en commandes simples et composées.
  4. Le shell effectue diverses extensions (séparément) ...
  5. Le shell effectue la redirection et supprime les opérateurs de redirection et leurs opérandes de la liste des paramètres.
  6. Le shell exécute une fonction, un fichier intégré, un fichier exécutable ou un script ...
  7. Le shell attend éventuellement que la commande soit terminée et recueille le statut de sortie.

A l'étape 6, une commande intégrée sera exécutée.
À l'étape 6, eval renvoie la ligne traitée à l'étape 1.
Il s'agit de la seule condition dans laquelle la séquence d'exécution revient.

C'est pourquoi je dis: Avec eval, une ligne d'entrée est analysée deux fois .

Effets de l'analyse deux fois.

La première.

Et l'effet le plus important à comprendre. Est - ce une conséquence de la première fois qu'une ligne est soumise aux sept étapes shell ci - dessus, est cite . À l'étape 4 (extensions), il y a également une séquence d'étapes pour effectuer toutes les extensions , dont la dernière est la suppression des devis :

Le retrait des devis doit toujours être effectué en dernier.

Donc, toujours, il y a un niveau de cotation supprimé.

Seconde.

En conséquence de ce premier effet, des parties supplémentaires / différentes de la ligne sont exposées à l'analyse syntaxique du shell et à toutes les autres étapes.

Exemple.

Indirection.

Cela permet d’exécuter des extensions indirectes:

a=b b=c    ;    eval echo \$$a            ### shall produce "c"

Pourquoi? Parce que sur la première boucle, la première $est citée.
En tant que tel, il est ignoré pour les extensions du shell.
Le prochain $avec le nom a est développé pour produire "b".
Ensuite, un niveau de citation est supprimé, ce qui rend le premier $non cité .
Fin de la première boucle.

C'est ensuite sur la seconde boucle que la chaîne $best lue par le shell.
Puis étendu à "c"
et donné comme argument à echo.

Pour "voir" ce que eval produira sur la première boucle (à réévaluer), utilisez echo. Ou toute commande / script / programme qui montre clairement les arguments:

$ a=b b=c
$ eval echo \$$a;
c

Remplacez eval par echo pour "voir" ce qui se passe:

$ echo echo \$$a
echo $b

Il est également possible d'afficher toutes les "parties" d'une ligne avec:

$ printf '<%s> ' echo \$$a
<echo> <$b>

Dans cet exemple, il ne s'agit que d'un écho et d'une variable, mais souvenez-vous-en pour vous aider à évaluer des cas plus complexes.

Une correction

Il faut dire que: il y a une erreur dans le code ci-dessus, pouvez-vous le voir?.
Facile: il manque des citations.

Comment? tu peux demander. Simple, changeons les variables (pas le code):

$ a=b b="hi     jk"
$ eval echo \$$a
hi jk

Voir les espaces manquants?
C'est parce que la valeur à l'intérieur a $bété divisée par le shell.

Si cela ne vous convainc pas, essayez ceci:

$ a=b b="hi  *  jk"
$ eval echo \$$a              ### warning this will expand to the list  
                              ### of all files in the present directory.

Pourquoi?

Citations manquantes. Pour que cela fonctionne correctement (ajoutez "$a"des \"devis internes et externes ).
Essayez ceci (est parfaitement sûr):

$ a=b b="hi      *       jk"
$ eval echo \" \$"$a" \"
hi      *       jk

A propos du manuel:

Il n'y a pas de page de manuel pour cela ..

Non, il n'y a pas de page de manuel indépendante pour cela. La recherche de manuel avec man -f evalou même apropos evalne montre aucune entrée.

Il est inclus à l'intérieur man bash. Comme est intégré.
Recherchez "SHELL BUILTIN COMMANDS" puis "eval".

Un moyen plus simple d’obtenir de l’aide est le suivant: Dans bash, vous pouvez help evalvoir l’aide de la fonction intégrée.

Pourquoi eval est-il appelé le mal?

Parce qu'il s'agit d'un texte contraignant à coder de manière dynamique.

En d'autres termes: il convertit la liste de ses arguments (et / ou développements de tels arguments) en une ligne exécutée. Si, pour une raison quelconque, un argument a été défini par un attaquant, vous allez exécuter du code d’attaquant.

Ou encore plus simplement, avec eval, vous indiquez à quiconque a défini la valeur d'un ou plusieurs arguments:

Allez, assieds-toi ici et tape n'importe quelle ligne de commande, je l'exécuterai avec mes pouvoirs.

Est-ce dangereux? Cela devrait être clair pour tout le monde.

La règle de sécurité pour eval devrait être:
N'exécutez eval que sur les variables auxquelles vous avez attribué sa valeur.

Lire plus de détails ici .


10

evalest une caractéristique des langues les plus interprétées ( TCL, python, ruby...), non seulement des coquilles. Il est utilisé pour évaluer le code de manière dynamique.

Dans les shells, il est implémenté en tant que commande intégrée au shell.

Fondamentalement, evalprend une chaîne en tant qu'argument et évalue / interprète le code qu'il contient. Dans les shells, evalpeut prendre plus d'un argument, mais il evalsuffit de les concaténer pour former la chaîne à évaluer.

C'est très puissant car vous pouvez construire du code de manière dynamique et l'exécuter, chose que vous ne pouvez pas faire dans des langages compilés comme C.

Comme:

varname=$1 varvalue=$2
eval "$varname=\$varvalue" # evaluate a string like "foo=$varvalue"
                           # which in Bourne-like shell language
                           # is a variable assignment.

Mais c’est aussi dangereux, car il est important de nettoyer les parties dynamiques (fournies de l’extérieur) de ce qui est transféré evalcar elles sont interprétées comme du code shell.

Par exemple, ci-dessus, si $1est evil-command; var, evalfinirait par évaluer le evil-command; var=$varvaluecode shell et ensuite l'exécuter evil-command.

La perversité de evalest souvent exagérée.

OK, c'est dangereux, mais au moins on sait que c'est dangereux.

Beaucoup d'autres commandes évaluera le code shell dans ses arguments , sinon aseptisé, comme ( en fonction de la coquille), [alias test, export, printf, GNU sed, awket bien sûr sh/ bash/ perlet tous les interprètes ...

Des exemples (ici en utilisant unamecomme evil-commandet $aen externe fourni des données hygiénisées):

$ a='$(uname>&2)' sh -c 'eval "echo $a"'
Linux

$ a='x[0$(uname>&2)]' mksh -c 'export "$a=$b"'
Linux
$ a='x[0$(uname>&2)]' ksh93 -c 'printf "%d\n" "$a"'
Linux
0
$ a='x[0$(uname>&2)]' ksh93 -c '[ "$a" -gt 0 ]'
Linux
$ a=$'bar/g;e uname>&2\n;s//'; echo foo | sed "s/foo/$a/g"
Linux
bar
$ a='";system("uname");"'; awk "BEGIN{print \"$a\"}"

Linux
$ a=';uname'; sh -c "echo $a"

Linux

Ces commandes sed, export... pourraient être considérées comme plus dangereuses car, même si c'est évident eval "$var", le contenu de $varsera évalué en tant que code shell, ce n'est pas si évident avec sed "s/foo/$var/"ou export "$var=value"ou [ "$var" -gt 0 ]. La dangerosité est la même, mais elle est dissimulée dans ces autres commandes.


@BinaryZebra, c'est sedcomme si evalon passait une chaîne contenue dans une variable, et pour les deux, le contenu de cette chaîne finit par être évalué en tant que code shell, donc sedc'est aussi dangereux que eval, c'est ce que je dis. sedest en train de passer une chaîne contenant uname(uname n’a pas encore été exécuté) et par l’appel de sed, la commande uname est exécutée. J'aime pour eval. En fait sed 's/foo/$a/g', vous ne transmettez pas de données non normalisées à sed, ce n'est pas ce dont nous parlons ici.
Stéphane Chazelas

2

Cet exemple peut éclairer un peu:

#!/bin/bash
VAR1=25
VAR2='$VAR1'
VAR3='$VAR2'
echo "$VAR3"
eval echo "$VAR3"
eval eval echo "$VAR3"

Sortie du script ci-dessus:

$VAR2
$VAR1
25

Merci pour votre contribution, mais, aussi divertissants qu’ils soient, nous ne sommes pas intéressés par la compilation d’une liste d’exemples (légèrement différents) d’utilisation eval. Pensez-vous que certains aspects fondamentaux et critiques de la fonctionnalité evalne sont pas abordés dans les réponses existantes? Si oui, expliquez -le et utilisez l'exemple pour illustrer votre explication. S'il vous plaît ne répondez pas dans les commentaires; éditez  votre réponse pour la rendre plus claire et plus complète.
Scott
En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.