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
.
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
$foo
s hodnotou '10'
a $x
s hodnotou 'foo'
.$y
, který se skládá z řetězce '$foo'
. Znak dolaru musí být označen znakem '$'
.echo $y
.'$foo'
eval
. Nejprve vyhodnotí $x
do řetězce 'foo'
. Nyní máme prohlášení y=$foo
které bude vyhodnoceno uživateli y=10
.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
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
:
[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é.
[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.
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í.
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 >
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.
Jednoduše řečeno: vytvoří vstupní řádek, který má být analyzován dvakrát .
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í
- Shell čte svůj vstup ....
- Shell rozdělí vstup na tokeny: slova a operátory
- Shell analyzuje vstup do jednoduchých a složených příkazů.
- Shell provádí různé expanze (samostatně) ...
- Shell provádí přesměrování a odebere operátory přesměrování a jejich operandy ze seznamu parametrů.
- Shell provádí funkci, vestavěný, spustitelný soubor nebo skript ...
- 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 .
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.
V důsledku tohoto prvního účinku se další/odlišné části linky vystaví analýze Shell a všem dalším krokům.
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ů.
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.
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
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é.
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 .
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á.
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