it-swarm-eu.dev

Co je příkaz „eval“ v bashu?

Co můžete udělat s příkazem eval? Proč je to užitečné? Je to nějaká vestavěná funkce v bashu? Neexistuje žádná stránka man.

210
LanceBaynes

eval je součástí POSIX. Je to rozhraní, které může být zabudováno do Shell.

Je popsán v „Příručce pro programátory POSIX“: http://www.unix.com/man-page/posix/1posix/eval/

eval - construct command by concatenating arguments

Převezme argument a vytvoří příkaz, který bude vykonán Shellem. Toto je příklad manuálu:

1) foo=10 x=foo
2) y='$'$x
3) echo $y
4) $foo
5) eval y='$'$x
6) echo $y
7) 10
  1. V prvním řádku definujete $foo s hodnotou '10' a $x s hodnotou 'foo'.
  2. Nyní definujte $y, který se skládá z řetězce '$foo'. Znak dolaru musí být označen znakem '$'.
  3. Chcete-li zkontrolovat výsledek, echo $y.
  4. Výsledkem bude řetězec '$foo'
  5. Nyní opakujeme přiřazení s eval. Nejprve vyhodnotí $x do řetězce 'foo'. Nyní máme prohlášení y=$foo které bude vyhodnoceno uživateli y=10.
  6. Výsledek echo $y je nyní hodnota '10'.

Toto je běžná funkce v mnoha jazycích, např. Perl a JavaScript. Podívejte se na perldoc eval pro další příklady: http://perldoc.Perl.org/functions/eval.html

150
echox

Ano, eval je interní interní příkaz, takže je popsán na stránce bash man.

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.

Obvykle se používá v kombinaci s Substituce příkazu . Bez explicitního eval se Shell pokusí provést výsledek substituce příkazu, nikoli ) vyhodnotit to.

Řekněme, že chcete kódovat ekvivalent VAR=value; echo $VAR. Všimněte si rozdílu ve způsobu, jakým Shell zpracovává spisy echo VAR=value:

  1. [email protected]:~> $( echo VAR=value )
    bash: VAR=value: command not found
    [email protected]:~> echo $VAR
    <empty line>
    

    Shell se pokouší provést echo a VAR=value jako dva samostatné příkazy. Vyvolá chybu o druhém řetězci. Zadání zůstává neúčinné.

  2. [email protected]:~> eval $( echo VAR=value )
    [email protected]:~> echo $VAR
    value
    
    Shell sloučí (zřetězí) dva řetězce echo a VAR=value, analyzuje tuto jedinou jednotku podle příslušných pravidel a provede ji.

V neposlední řadě může být eval velmi nebezpečným příkazem. Jakýkoli vstup do příkazu eval musí být pečlivě zkontrolován, aby nedošlo k problémům se zabezpečením.

65
andcoz

eval nemá žádnou manuálovou stránku, protože se nejedná o samostatný externí příkaz, ale o vestavěný Shell, což znamená příkaz interní a známý pouze Shellem (bash). Příslušná část manuálové stránky bash říká:

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

Navíc výstup, pokud help eval je:

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.

eval je výkonný příkaz, a pokud jej hodláte použít, měli byste být velmi opatrní, abyste odvedli možná bezpečnostní rizika , která s ním souvisí.

19
jw013

Příkaz eval říká Shellovi, aby bral evalovy argumenty jako příkaz a spustil je přes příkazovou řádku. Je to užitečné v níže uvedené situaci:

Pokud ve skriptu definujete příkaz do proměnné a později jej chcete použít, měli byste použít 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 >
18
Nikhil Gupta

Co je eval?

eval je příkaz Shell, který je obvykle implementován jako zabudovaný.

V POSIXu je uveden jako součást z "2.14. Special Built-In Utilities" v položce "eval" .
Co je vestavěný znamená:

Termín "vestavěný" znamená, že Shell může spustit nástroj přímo a nemusí jej hledat.

Co to dělá?

Jednoduše řečeno: vytvoří vstupní řádek, který má být analyzován dvakrát .

Jak se to dělá?

Shell má sekvenci kroků, které následuje, aby „zpracoval“ linku. Mohli byste podívejte se na tento obrázek a uvědomit si, že eval je jediný řádek, který jde nahoru, zpět ke kroku 1, vlevo. Od popis POSIX :

2.1 Úvod do prostředí

  1. Shell čte svůj vstup ....
  2. Shell rozdělí vstup na tokeny: slova a operátory
  3. Shell analyzuje vstup do jednoduchých a složených příkazů.
  4. Shell provádí různé expanze (samostatně) ...
  5. Shell provádí přesměrování a odebere operátory přesměrování a jejich operandy ze seznamu parametrů.
  6. Shell provádí funkci, vestavěný, spustitelný soubor nebo skript ...
  7. Shell volitelně čeká na dokončení příkazu a shromáždí stav ukončení.

V kroku 6 bude provedeno zabudování.
V kroku 6 eval způsobí, že se zpracovaná linka vrátí zpět do kroku 1.
Je to jediná podmínka, za níž se prováděcí sekvence vrací.

Proto říkám: S evalem je vstupní řádek analyzován dvakrát .

Účinky analýzy dvakrát.

První.

A nejdůležitější účinek k pochopení. Je to jeden z důsledků, kdy je první řádek podroben sedmi výše popsaným Shellovým krokům, je citace . V kroku 4 (rozšíření) je také posloupnost kroků k provedení všech rozšíření , z nichž poslední je Odebrání nabídky :

Odebrání nabídky musí být vždy provedeno jako poslední.

Takže vždy existuje jedna úroveň citace odstraněna.

Druhý.

V důsledku tohoto prvního účinku se další/odlišné části linky vystaví analýze Shell a všem dalším krokům.

Příklad.

Indirection.

To umožňuje provádět nepřímé expanze:

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

Proč? Protože na první smyčce, první $ je citován.
Jako takový, to je ignorováno pro expanze Shell.
Další $ s názvem a je rozšířeno na "b".
Poté je odstraněna jedna úroveň citace, takže první $ nekótované.
Konec první smyčky.

V druhé smyčce je pak řetězec $b čte Shell.
Poté se rozšířilo na „c“
A uveden jako argument k echo.

Chcete-li „vidět“, co eval vytvoří v první smyčce (bude znovu vyhodnoceno), použijte echo. Nebo jakýkoli příkaz/skript/program, který jasně ukazuje argumenty:

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

Nahraďte eval za echo, abyste viděli, co se děje:

$ echo echo \$$a
echo $b

Je také možné zobrazit všechny „části“ řádku s:

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

Což je v tomto příkladu pouze jedna ozvěna a jedna proměnná, ale pamatujte, že to pomůže při hodnocení složitějších případů.

Oprava.

Je třeba říci, že: v kódu výše je chyba, vidíte to ?.
Snadné: chybí některé citace.

Jak? můžete se zeptat. Jednoduché, změňme proměnné (ne kód):

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

Vidíte chybějící prostory?
Je to proto, že hodnota uvnitř $b byl rozdělen Shell.

Pokud vás to nepřesvědčí, zkuste toto:

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

Proč?

Chybějící citace. Aby to fungovalo správně (přidejte interní "$a"a externí \" citáty).
Zkuste to (je naprosto bezpečné):

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

O manuálu:

Neexistuje žádná mužská stránka.

Ne, neexistuje nezávislá manuální stránka. Hledání manuálu pomocí man -f eval nebo dokonce apropos eval nezobrazí žádný záznam.

Je součástí uvnitř man bash. Jak je vestavěný.
Vyhledejte „Shell BUILTIN COMMANDS“ a poté „eval“.

Snadnější způsob, jak získat pomoc, je: V bash, můžete udělat help eval pro zobrazení nápovědy pro vestavěné.

Proč se eval nazývá zlo?

Protože je to dynamicky vázaný text.

Jinými slovy: převede seznam svých argumentů (nebo rozšíření takových argumentů) na vykonanou linii. Pokud útočník z nějakého důvodu zadal argument, provedete kód útočníka.

Nebo ještě jednodušší, s eval říkáte, kdo definoval hodnotu jednoho nebo několika argumentů:

No tak, posaďte se sem a napište libovolný příkazový řádek, provedu jej svými schopnostmi!

Je to nebezpečné? Pro každého by mělo být jasné, že to je.

Bezpečnostní pravidlo pro eval by mělo být:
Eval vykonejte pouze u proměnných, kterým jste dali jeho hodnotu.

Číst více podrobností zde .

12
user79743

eval je funkce většiny interpretovaných jazyků (TCL, python, Ruby...), nejen pouzder. Používá se k dynamickému vyhodnocení kódu.

Ve skořápce je implementován jako vestavěný příkaz Shell.

V podstatě eval vezme řetězec jako argument a vyhodnotí/interpretuje kód v něm. Ve skořápkách může eval trvat více než jeden argument, ale eval je pouze spojí, aby vytvořil řetězec, který má být vyhodnocen.

Je to velmi výkonné, protože můžete vytvářet kód dynamicky a spouštět jej, což ve kompilovaných jazycích, jako je C.

Jako:

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

Je však také nebezpečné, protože je důležité dezinfikovat dynamické (externě poskytované) části toho, co se předává eval, právě proto, že se interpretuje jako Shellův kód.

Například výše, pokud $1 je evil-command; var, eval by nakonec skončilo vyhodnocením evil-command; var=$varvalue Shell code a potom spusťte evil-command.

Zlo eval je často přehnané.

Dobře, je to nebezpečné, ale alespoň víme, že je to nebezpečné.

Mnoho dalších příkazů vyhodnotí kód Shell ve svých argumentech, pokud není dezinfikován, například (v závislosti na prostředí), [ aka test, export, printf, GNU sed, awk a z kurz sh/bash/Perl a všichni tlumočníci ...

Příklady (zde pomocí uname jako evil-command a $a jako externě poskytnuté neanitizované údaje):

$ 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

Tyto příkazy sed, export... by mohly být považovány za nebezpečnější, protože je to zřejmé eval "$var" způsobí obsah $var být vyhodnocen jako Shellův kód, není to s sed "s/foo/$var/" nebo export "$var=value" nebo [ "$var" -gt 0 ]. Nebezpečnost je stejná, ale v ostatních příkazech je skrytá.

11
Stéphane Chazelas

Tento příklad může vrhnout nějaké světlo:

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

Výstup výše uvedeného skriptu:

$VAR2
$VAR1
25
5
LoMaPh