Почему замена eval на declare (для создания динамических переменных )приводит к пустой переменной?

У вас опечатка. Вам не хватает $перед(which npm)

Так ты хочешь$(which npm)

Структура $(...)означает «запустить команду внутри скобок и вернуть результат»

3
04.03.2021, 15:19
1 ответ

declare(как и typesetдругих оболочек; также понимается как bashкак псевдоним для declare), объявляет переменную в текущей области видимости (и может устанавливать тип и/или значение ).

Итак, здесь вы должны объявить переменную, которая является локальной для функции create_variable_for_arch. Когда эта функция вернется, эта переменная исчезнет.

bash's declare/ typesetимеет опцию -gдля объявления переменной глобальной ), но вы также не можете использовать ее, поскольку она объявляет переменную (и устанавливает ее тип и/или значение )во внешней -наибольшей области действия, в отличие от области действия вызывающей функции, поэтому там довольно бесполезно (, оно более полезно в mksh/ zsh/ yashгде он только пропускает , делая его локальным или с ksh93, который имеет статическую область видимости, см. . Что делают `объявлять имя `и `объявлять -g `? подробнее ).

Таким образом, вы можете либо использовать eval, либо использовать namerefs :

.
create_variable_for_arch() {
  if [ "$_run_for_arch" = mac ]; then
    eval "$1=\$2"
  else
    eval "$1=\$3"
  fi
}

Или, предполагая, что $_run_for_archявляется константой в вашем скрипте:

if [ "$_run_for_arch" = "mac" ]; then
  create_variable_for_arch() { eval "$1=\$2"; }
else
  create_variable_for_arch() { eval "$1=\$3"; }
fi

Или с именами:

create_variable_for_arch() {
  typeset -n _var_name="$1"
  if [ "$_run_for_arch" = mac ]; then
    _var_name=$2
  else
    _var_name=$3
  fi
}

Часто (справедливо )рекомендуется избегать evalиз соображений безопасности, но evalбезопасен при правильном использовании. declareи namerefsбыли бы здесь небезопасны при неправильном использовании, поскольку они оба могут также оценивать код.

Все:

f() { eval "$1=\$2"; }
f() { declare "$1=$2"; }
f() { declare -n v="$1"; v=$2; }

Будет выполняться команда reboot, если она вызывается с:

f 'a[$(reboot)]' value

Важно убедиться, что первым аргументом является имя переменной, чтобы избежать уязвимости, связанной с выполнением произвольной команды.

f() { declare $1=$2; }

было бы гораздо хуже. Поскольку эти расширения параметров не заключены в кавычки, они подлежат разделению + подстановке, поэтому даже содержимое $2может в конечном итоге оцениваться как шелл-код, как в:

f var 'foo a[$(reboot)]='
4
18.03.2021, 22:27

Теги

Похожие вопросы