Was ist der "Eval" -Befehl in Bash?


176

Was können Sie mit dem evalBefehl machen? Warum ist es nützlich? Ist es eine Art integrierte Funktion in Bash? Es gibt keine manSeite dafür ..


28
Hier type commanderfahren Sie, welcher Typ ein Befehl ist. ( type evalin diesem Fall)
rozcietrzewiacz

9
"Eval ist eine Shell Builtin"
Nuno Rafael Figueiredo

3
help evalum "man" Seite von deiner Shell zu bekommen
m-ric

eval ist ein bash-builtin und wird in der man-Seite von bash dokumentiert. Also einfach "man bash" eingeben und nach dem entsprechenden Abschnitt für eval suchen. Dies gilt auch für andere Bash-Builtins.
Dirk Thannhäuser

Antworten:


132

evalist ein Teil von POSIX. Es ist eine Schnittstelle, die eine eingebaute Shell sein kann.

Es ist im "POSIX Programmer's Manual" beschrieben: http://www.unix.com/man-page/posix/1posix/eval/

eval - construct command by concatenating arguments

Es nimmt ein Argument und erstellt daraus einen Befehl, der von der Shell ausgeführt wird. Dies ist das Beispiel der Manpage:

1) foo=10 x=foo
2) y='$'$x
3) echo $y
4) $foo
5) eval y='$'$x
6) echo $y
7) 10
  1. In der ersten Zeile definieren Sie $foomit dem Wert '10'und $xmit dem Wert 'foo'.
  2. Definieren Sie nun $y, welches aus dem String besteht '$foo'. Das Dollarzeichen muss mit maskiert werden '$'.
  3. Um zu prüfen, das Ergebnis echo $y.
  4. Das Ergebnis ist der String '$foo'
  5. Nun wiederholen wir die Zuordnung mit eval. Es wird zuerst $xdie Zeichenfolge ausgewertet 'foo'. Jetzt haben wir die Anweisung, y=$foodie ausgewertet wird y=10.
  6. Das Ergebnis von echo $yist jetzt der Wert '10'.

Dies ist eine in vielen Sprachen übliche Funktion, z. B. Perl und JavaScript. Weitere Beispiele finden Sie in perldoc eval: http://perldoc.perl.org/functions/eval.html


4
In der Shell-Terminologie evalist dies eine integrierte Funktion, keine Funktion. In der Praxis verhalten sich eingebaute Funktionen ähnlich wie Funktionen, die keine sprachspezifische Definition haben, aber nicht ganz (wie sich zeigt, wenn Sie so verdreht sind, dass Sie eine aufgerufene Funktion definieren eval).
Gilles

Danke, das wurde behoben :-)
Echox

4
Was ist der Unterschied zwischen eval und backticks?
JohnyTex

5
Backticks sind eine Abkürzung für die Ausführung einer weiteren vollständigen Shell. Das bedeutet, dass in Ihrem Skript ein weiterer untergeordneter Bash / Sh-Prozess ausgeführt wird.
Aaron R.

Warum bringt echo $ y (Stufe 3) foo (10) anstelle von $ foo zurück? (dh nur der Wert von foo anstelle des Strings $ + der Wert von foo)?
JohnDoea

60

Ja, es evalhandelt sich um einen internen bash-Befehl, der in der bashManpage beschrieben wird.

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.

Normalerweise wird es in Kombination mit einer Befehlsersetzung verwendet . Ohne einen expliziten Befehl evalversucht die Shell , das Ergebnis einer Befehlssubstitution auszuführen und nicht auszuwerten .

Angenommen, Sie möchten ein Äquivalent von codieren VAR=value; echo $VAR. Beachten Sie den Unterschied in der Art und Weise, wie die Shell die folgenden Schriften verarbeitet echo VAR=value:

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

    Die Shell versucht, echound VAR=valueals zwei separate Befehle auszuführen. Es wird ein Fehler bezüglich der zweiten Zeichenfolge ausgegeben. Die Abtretung bleibt unwirksam.

  2. andcoz@...:~> eval $( echo VAR=value )
    andcoz@...:~> echo $VAR
    value
    Die Shell führt die beiden Zeichenfolgen zusammen (verkettet sie) echound VAR=valueanalysiert diese einzelne Einheit gemäß den entsprechenden Regeln und führt sie aus.

Last but not least evalkann ein sehr gefährlicher Befehl sein. Alle Eingaben in einen evalBefehl müssen sorgfältig geprüft werden, um Sicherheitsprobleme zu vermeiden.


18

evalhat keine Manpage, da es sich nicht um einen separaten externen Befehl handelt, sondern um eine integrierte Shell, dh einen internen Befehl, der nur der shell ( bash) bekannt ist. Der relevante Teil der bashManpage sagt:

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

Zusätzlich ist die Ausgabe wenn help eval:

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.

evalist ein leistungsfähiger Befehl, und wenn Sie ihn verwenden möchten, sollten Sie sehr vorsichtig sein, um die damit verbundenen möglichen Sicherheitsrisiken zu vermeiden .


16

Die eval-Anweisung weist die Shell an, die Argumente von eval als Befehl zu nehmen und über die Befehlszeile auszuführen. Dies ist in folgenden Situationen nützlich:

Wenn Sie in Ihrem Skript einen Befehl in einer Variablen definieren und später diesen Befehl verwenden möchten, sollten Sie eval verwenden:

/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
Der Kommentar in Zeile 4 Ihres Beispiels ist falsch: Es sollte lauten: "Der obige Befehl hat nicht funktioniert, weil bash versucht hat, einen aufgerufenen Befehl zu finden ls | more. Mit anderen Worten: Der einzelne Befehlsname bestand aus neun Zeichen, einschließlich der Leerzeichen und des Pipe-Symbols .
cfi

Ich habe genau das gleiche Verhalten wie er. bash --version == GNU bash, version 3.2.57 (1) -release (x86_64-apple-darwin18)
Alexander Bird

10

Was ist eval?

eval ist ein Shell-Befehl, der normalerweise als eingebauter Befehl implementiert wird.

In POSIX ist es als Teil von "2.14. Special Built-In Utilities" unter dem Eintrag "eval" aufgeführt .
Was Builtin bedeutet, ist:

Der Begriff "eingebaut" impliziert, dass die Shell das Dienstprogramm direkt ausführen kann und nicht danach suchen muss.

Was tut es?

In einfachen Worten: Lässt eine Eingabezeile zweimal analysiert werden .

Wie macht es das?

Die Shell hat eine Abfolge von Schritten, die zum "Verarbeiten" einer Zeile ausgeführt werden. Sie können sich dieses Bild ansehen und feststellen, dass eval die einzige Zeile ist, die nach oben zurück zu Schritt 1 auf der linken Seite führt. Aus der POSIX-Beschreibung :

2.1 Shell Einführung

  1. Die Shell liest ihre Eingabe ....
  2. Die Shell unterteilt die Eingabe in Token: Wörter und Operatoren
  3. Die Shell analysiert die Eingabe in einfache und zusammengesetzte Befehle.
  4. Die Shell führt verschiedene Erweiterungen (separat) durch ...
  5. Die Shell führt eine Umleitung durch und entfernt Umleitungsoperatoren und deren Operanden aus der Parameterliste.
  6. Die Shell führt eine Funktion, eine eingebaute ausführbare Datei oder ein Skript aus ...
  7. Die Shell wartet optional auf den Abschluss des Befehls und erfasst den Beendigungsstatus.

In Schritt 6 wird eine eingebaute ausgeführt.
In Schritt 6 bewirkt eval, dass die verarbeitete Zeile zu Schritt 1 zurückgesendet wird.
Dies ist die einzige Bedingung, unter der die Ausführungssequenz zurückgeht.

Deshalb sage ich: Bei eval wird eine Eingabezeile zweimal analysiert .

Auswirkungen der zweimaligen Analyse.

Der Erste.

Und wichtigste Wirkung zu verstehen. Ist das eine Konsequenz des ersten Males, dass eine Zeile den oben gezeigten sieben Shell-Schritten unterliegt, so wird zitiert . Innerhalb von Schritt 4 (Erweiterungen) gibt es auch eine Abfolge von Schritten, um alle Erweiterungen durchzuführen , von denen der letzte das Entfernen von Zitaten ist :

Das Entfernen des Angebots erfolgt immer zuletzt.

Es wird also immer eine Quote-Ebene entfernt.

Zweite.

Infolge dieses ersten Effekts werden zusätzliche / unterschiedliche Teile der Linie dem Shell-Parsing und allen anderen Schritten ausgesetzt.

Beispiel.

Indirektion.

Damit können indirekte Erweiterungen durchgeführt werden:

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

Warum? Denn in der ersten Schleife wird die erste $zitiert.
Als solches wird es für Erweiterungen durch die Shell ignoriert.
Das nächste $mit dem Namen a wird erweitert, um "b" zu erzeugen.
Dann wird eine Zitierebene entfernt, wodurch die erste $nicht zitiert wird .
Ende der ersten Schleife.

In der zweiten Schleife wird die Zeichenfolge $bdann von der Shell gelesen.
Dann auf "c" erweitert
und als Argument an gegeben echo.

Um zu "sehen", was eval in der ersten Schleife erzeugt (um erneut ausgewertet zu werden), verwenden Sie echo. Oder ein Befehl / Skript / Programm, das die Argumente klar anzeigt:

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

Ersetzen Sie eval durch echo, um zu sehen, was gerade passiert:

$ echo echo \$$a
echo $b

Es ist auch möglich, alle "Teile" einer Zeile anzuzeigen mit:

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

Dies ist in diesem Beispiel nur ein Echo und eine Variable. Denken Sie jedoch daran, dass dies bei der Bewertung komplexerer Fälle hilfreich ist.

Eine Korrektur.

Es muss gesagt werden, dass: Es gibt einen Fehler im obigen Code, können Sie es sehen ?.
Ganz einfach: Es fehlen einige Anführungszeichen.

Wie? du darfst fragen. Einfach, lassen Sie uns die Variablen ändern (nicht den Code):

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

Sehen Sie die fehlenden Leerzeichen?
Das liegt daran, dass der innere Wert $bvon der Shell geteilt wurde.

Wenn Sie das nicht überzeugt, versuchen Sie Folgendes:

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

Warum?

Fehlende Anführungszeichen. Damit es richtig funktioniert (fügen Sie interne "$a"und externe \"Anführungszeichen hinzu).
Versuchen Sie dies (ist absolut sicher):

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

Über das Handbuch:

Es gibt keine Manpage dafür.

Nein, dafür gibt es keine eigenständige Manpage. Die Suche nach Handbuch mit man -f evaloder apropos evalohne Eintrag.

Es ist im Inneren enthalten man bash. Wie ist jeder eingebaut.
Suchen Sie nach "SHELL BUILTIN COMMANDS" und dann nach "eval".

Eine einfachere Möglichkeit, Hilfe zu erhalten, ist: In bash können Sie help evaldie Hilfe für das integrierte Programm anzeigen .

Warum heißt eval böse?

Weil es Text bindet, um dynamisch zu codieren.

Mit anderen Worten: Es konvertiert die Liste seiner Argumente (und / oder Erweiterungen solcher Argumente) in eine ausgeführte Zeile. Wenn ein Angreifer aus irgendeinem Grund ein Argument festgelegt hat, führen Sie Angreifercode aus.

Oder noch einfacher: Mit eval sagen Sie, wer den Wert eines oder mehrerer Argumente definiert hat:

Komm schon, setz dich hier und tippe eine beliebige Befehlszeile, ich werde sie mit meinen Kräften ausführen.

Ist das gefährlich Sollte für alle klar sein, dass es ist.

Die Sicherheitsregel für eval sollte lauten:
Führen Sie eval nur für Variablen aus, denen Sie den Wert gegeben haben.

Lesen Sie hier mehr Details .


10

evalist ein Merkmal der meisten interpretierten Sprachen ( TCL, python, ruby...), nicht nur Muscheln. Es wird verwendet, um Code dynamisch auszuwerten.

In Shells wird es als eingebauter Shell-Befehl implementiert.

Nimmt im Grunde genommen evaleinen String als Argument und wertet / interpretiert den darin enthaltenen Code aus. In Shells evalkönnen mehrere Argumente verwendet werden, diese werden jedoch evalnur verkettet, um die auszuwertende Zeichenfolge zu bilden.

Es ist sehr leistungsstark, da Sie Code dynamisch erstellen und ausführen können, was in kompilierten Sprachen wie C nicht möglich ist.

Mögen:

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

Aber es ist auch gefährlich , wie es ist wichtig , die dynamischen (extern zur Verfügung gestellt) Teile zu sanieren , was vergangen ist evalaus dem Grunde , sie als Shell - Code interpretiert wird .

Zum Beispiel, wenn oben $1ist evil-command; var, evalwürde am Ende-up des Auswertung evil-command; var=$varvalueShell - Code und dann die ausgeführt evil-command.

Die Bösartigkeit von evalist oft übertrieben.

OK, es ist gefährlich, aber zumindest wissen wir, dass es gefährlich ist.

Viele andere Befehle Shell - Code in ihre Argumente zu bewerten , wenn nicht desinfiziert, wie ( in Abhängigkeit von der Schale), [auch bekannt als test, export, printf, GNU sed, awkund natürlich sh/ bash/ perlund alle Dolmetscher ...

Beispiele (hier unter Verwendung unameder evil-commandund $aals extern zur Verfügung gestellten nicht bereinigten Daten):

$ 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

Diese sed, export... -Befehle könnten als gefährlicher angesehen werden, da eval "$var"der Inhalt von zwar offensichtlich $varals Shell-Code ausgewertet wird, aber mit sed "s/foo/$var/"oder export "$var=value"oder nicht so offensichtlich ist [ "$var" -gt 0 ]. Die Gefährlichkeit ist dieselbe, aber sie ist in diesen anderen Befehlen verborgen.


@BinaryZebra, sedwie evalwird eine Zeichenkette in einer Variablen enthalten sind vergangen, und sowohl für den Inhalt dieser Zeichenfolge endet als Shell - Code ausgewertet werden, so sedgefährlich ist wie eval, das ist , was ich sage. sedwird ein String übergeben, der enthält uname(uname wurde bisher noch nicht ausgeführt) und durch den Aufruf von sedwird der Befehl uname ausgeführt. Wie für eval. In sed 's/foo/$a/g', vorbei sind Sie nicht aufpoliert Daten sed, das ist nicht das, was wir hier reden.
Stéphane Chazelas

2

Dieses Beispiel könnte etwas Licht ins Dunkel bringen:

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

Ausgabe des obigen Skripts:

$VAR2
$VAR1
25

Vielen Dank für Ihren Beitrag, aber so unterhaltsam sie auch sind, wir sind nicht wirklich daran interessiert, eine Liste von (leicht abweichenden) Anwendungsbeispielen zusammenzustellen eval. Glauben Sie, dass es einen grundlegenden, kritischen Aspekt der Funktionalität evalgibt, der in den vorhandenen Antworten nicht behandelt wird? Wenn ja, erklären Sie es und veranschaulichen Sie Ihre Erklärung anhand des Beispiels. Bitte antworten Sie nicht in Kommentaren; Bearbeiten Sie  Ihre Antwort, um sie klarer und vollständiger zu gestalten.
Scott
Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.