Хороший спосіб роботи eval- це замінити його echoна тестування. echoі evalпрацювати так само (якщо ми відкладемо \xрозширення, здійснене деякими echoреалізаціями, такими як bash's за певних умов).
Обидві команди з'єднують свої аргументи з одним проміжком між ними. Різниця полягає в тому, що echo відображає результат, тоді як eval оцінює / інтерпретує як оболонку коду результату.
Отже, щоб побачити, який код оболонки
eval $(echo $var_name=$var_value)
Ви можете оцінити, ви можете запустити:
$ echo $(echo $var_name=$var_value)
fruit=blue orange
Це не те, що ти хочеш, а те, що ти хочеш:
fruit=$var_value
Також використовувати $(echo ...)тут не має сенсу.
Щоб вивести вищезазначене, слід виконати:
$ echo "$var_name=\$var_value"
fruit=$var_value
Отже, для його тлумачення це просто:
eval "$var_name=\$var_value"
Зауважте, що він також може бути використаний для встановлення окремих елементів масиву:
var_name='myarray[23]'
var_value='something'
eval "$var_name=\$var_value"
Як говорили інші, якщо вам не важливо, щоб ваш код був bashконкретним, ви можете використовувати declareяк:
declare "$var_name=$var_value"
Однак зауважте, що він має деякі побічні ефекти.
Це обмежує область змінної функцією, в якій вона запущена. Отже, ви не можете використовувати її, наприклад, у таких речах, як:
setvar() {
var_name=$1 var_value=$2
declare "$var_name=$var_value"
}
setvar foo bar
Тому що це оголошує fooмінливу локальну на setvarтак було б марним.
bash-4.2додано -gпараметр для declareоголошення глобальної змінної, але це не те, чого ми хочемо, так як наш setvarвстановив би глобальний var на відміну від виклику, якщо викликає функцію, як у:
setvar() {
var_name=$1 var_value=$2
declare -g "$var_name=$var_value"
}
foo() {
local myvar
setvar myvar 'some value'
echo "1: $myvar"
}
foo
echo "2: $myvar"
який виведе:
1:
2: some value
Також зауважте, що в той час, declareяк викликається declare(фактично bashзапозичена концепція з typesetвбудованої оболонки Корна ), якщо змінна вже встановлена, declareне оголошує нову змінну, і спосіб виконання призначення залежить від типу змінної.
Наприклад:
varname=foo
varvalue='([PATH=1000]=something)'
declare "$varname=$varvalue"
призведе до іншого результату (і, можливо, матиме неприємні побічні ефекти), якщо varnameраніше він був оголошений як скалярний , масив або асоціативний масив .
evalцей спосіб неправильно. Ви розширюєтесь,$var_valueперш ніж передавати його,evalа значить, він буде інтерпретуватися як код оболонки! (спробуйте, наприклад, зvar_value="';:(){ :|:&};:'")