eval
vezme řetězec jako svůj argument a vyhodnotí jej, jako byste tento řetězec zadali na příkazovém řádku. (Pokud předáte několik argumentů, jsou nejprve spojeny mezerami mezi nimi.)
${$n}
je syntaktická chyba v bash. Uvnitř složených závorek můžete mít pouze název proměnné s nějakou možnou předponou a příponou, ale nemůžete mít libovolnou bash syntaxi a zejména nemůžete používat expanzi proměnné. Existuje způsob, jak říci „hodnotu proměnné, jejíž jméno je v této proměnné“, ačkoli:
echo ${!n}
one
$(…)
spustí příkaz zadaný v závorkách v dílčím prostředí (tj. v samostatném procesu, který zdědí všechna nastavení, jako jsou hodnoty proměnných, z aktuálního prostředí) a shromáždí jeho výstup. Takže echo $($n)
běží $n
jako příkaz shellu a zobrazí jeho výstup. Od $n
se vyhodnotí jako 1
, $($n)
pokusí se spustit příkaz 1
, který neexistuje.
eval echo \${$n}
spustí parametry předané do eval
. Po rozšíření jsou parametry echo
a ${1}
. Takže eval echo \${$n}
spustí příkaz echo ${1}
.
Všimněte si, že většinu času musíte kolem substitucí proměnných a substitucí příkazů používat dvojité uvozovky (tj. kdykoli se objeví $
):"$foo", "$(foo)"
. Náhrady proměnných a příkazů vždy umístěte do dvojitých uvozovek , pokud nevíte, že je musíte nechat vypnuté. Bez dvojitých uvozovek shell provede dělení pole (tj. rozdělí hodnotu proměnné nebo výstup z příkazu na samostatná slova) a poté každé slovo považuje za vzor zástupných znaků. Například:
$ ls
file1 file2 otherfile
$ set -- 'f* *'
$ echo "$1"
f* *
$ echo $1
file1 file2 file1 file2 otherfile
$ n=1
$ eval echo \${$n}
file1 file2 file1 file2 otherfile
$eval echo \"\${$n}\"
f* *
$ echo "${!n}"
f* *
eval
nepoužívá se příliš často. V některých shellech je nejběžnější použití k získání hodnoty proměnné, jejíž jméno není známo až do běhu. V bash to není nutné díky ${!VAR}
syntax. eval
je stále užitečné, když potřebujete vytvořit delší příkaz obsahující operátory, vyhrazená slova atd.
Jednoduše si eval představte jako „zhodnocení vašeho výrazu ještě jednou před provedením“
eval echo \${$n}
se změní na echo $1
po prvním kole hodnocení. Tři změny na upozornění:
\$
se stal$
(Je potřeba zpětné lomítko, jinak se pokusí vyhodnotit${$n}
, což znamená proměnnou s názvem{$n}
, což není povoleno)$n
byl vyhodnocen na1
eval
zmizel
Ve druhém kole je to v podstatě echo $1
které lze přímo provést.
Takže eval <some command>
nejprve vyhodnotí <some command>
(vyhodnocením zde myslím náhradní proměnné, nahraďte uvozené znaky správnými atd.) a poté spusťte výsledný výraz znovu.
eval
se používá, když chcete dynamicky vytvářet proměnné nebo číst výstupy z programů speciálně navržených pro takovéto čtení. Příklady viz http://mywiki.wooledge.org/BashFAQ/048. Odkaz také obsahuje některé typické způsoby, jak eval
se používá a rizika s ním spojená.
Podle mých zkušeností je "typické" použití eval pro spouštění příkazů, které generují příkazy shellu pro nastavení proměnných prostředí.
Možná máte systém, který používá kolekci proměnných prostředí, a máte skript nebo program, který určuje, které z nich by měly být nastaveny, a jejich hodnoty. Kdykoli spustíte skript nebo program, běží v rozvětveném procesu, takže vše, co dělá přímo s proměnnými prostředí, je při ukončení ztraceno. Ale tento skript nebo program může odeslat exportní příkazy do stdout.
Bez eval byste museli přesměrovat stdout do dočasného souboru, vytvořit zdroj dočasného souboru a poté jej odstranit. Pomocí eval můžete:
eval "$(script-or-program)"
Všimněte si, že uvozovky jsou důležité. Vezměte si tento (vymyšlený) příklad:
# activate.sh
echo 'I got activated!'
# test.py
print("export foo=bar/baz/womp")
print(". activate.sh")
$ eval $(python test.py)
bash: export: `.': not a valid identifier
bash: export: `activate.sh': not a valid identifier
$ eval "$(python test.py)"
I got activated!