Как присвоить содержащие пространство значения переменным в ударе с помощью оценки

Лучше как:

cd top &&
for i in */; do (cd -- "$i" && sha1sum -- * > sha1sum); done
19
13.09.2014, 01:07
5 ответов

Не использовать eval, использовать объявить

$ declare "$var_name=$var_value"
$ echo "fruit: >$fruit<"
fruit: >blue orange<
13
27.01.2020, 19:45

Если вы это сделаете:

eval "$name=\$val"

... и $ name содержит ; ] - или любой из нескольких других токенов, которые оболочка может интерпретировать как ограничивающие простую команду - которой предшествует правильный синтаксис оболочки, которая будет выполнена.

name='echo hi;varname' val='be careful with eval'
eval "$name=\$val" && echo "$varname"

ВЫВОД

hi
be careful with eval

Однако иногда можно разделить оценку и выполнение таких операторов. Например, псевдоним может использоваться для предварительной оценки команды. В следующем примере определение переменной сохраняется под псевдонимом , который может быть успешно объявлен только в том случае, если оцениваемая переменная $ nm не содержит байтов, не соответствующих буквенно-цифровым значениям ASCII или ] _ .

LC_OLD=$LC_ALL LC_ALL=C
alias "${nm##*[!_A-Z0-9a-z]*}=_$nm=\$val" &&
eval "${nm##[0-9]*}" && unalias "$nm"
LC_ALL=$LC_OLD

eval используется здесь для обработки вызова нового псевдонима из переменной. Но он вообще вызывается только в том случае, если предыдущее определение псевдонима было успешным, и хотя я знаю, что множество различных реализаций будут принимать множество различных типов значений для псевдонимов имен, я еще не встретил тот, который примет совершенно пустой.

Однако определение в псевдониме предназначено для _ $ nm , и это сделано для того, чтобы не перезаписывать важные значения среды. Я не знаю каких-либо примечательных значений среды, начинающихся с _ , и обычно это безопасная ставка для полу-частного объявления.

В любом случае, если определение псевдонима выполнено успешно, он объявит псевдоним , названный для значения $ nm . И eval вызовет этот псевдоним , только если он также не начинается с числа - иначе eval получит только нулевой аргумент. Таким образом, если оба условия выполняются, eval вызывает псевдоним и выполняется определение переменной, сохраненное в псевдониме, после чего новый псевдоним немедленно удаляется из хеш-таблицы.

1
27.01.2020, 19:45

Не используйте для этого eval; используйте declare.

var_name="fruit"
var_value="blue orange"
declare "$var_name=$var_value"

Обратите внимание, что разделение слов не является проблемой, так как все, что следует за =, рассматривается как значение с помощью declare, а не только как первое слово.

В bash 4.3 именованные ссылки делают это немного проще.

$ declare -n var_name=fruit
$ var_name="blue orange"
$ echo $fruit
blue orange

Вы можете заставить eval работать, но вы все равно не должны :). Использование eval - плохая привычка.

$ eval "$(printf "%q=%q" "$var_name" "$var_value")"
11
27.01.2020, 19:45

Хороший способ работы с eval - заменить его на echo для тестирования. echo и eval работают одинаково (если оставить в стороне расширение \ x , выполняемое некоторыми реализациями echo , такими как bash при некоторых условиях).

Обе команды соединяют свои аргументы одним пробелом между ними. Разница в том, что 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 для объявления , чтобы объявить глобальную переменную, но это не то, что мы хотим, поскольку наша setvar установит глобальную переменную в отличие от переменной вызывающей стороны, если вызывающая сторона была функцией, например:

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

Также обратите внимание, что while declare вызывается declare (на самом деле bash заимствовал концепцию из встроенного набора typeset оболочки Korn), если переменная уже установлена, declare не объявляет новую переменную, и способ выполнения присваивания зависит от типа переменной.

Например:

varname=foo
varvalue='([PATH=1000]=something)'
declare "$varname=$varvalue"

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

4
27.01.2020, 19:45

используйте мертвые кавычки, т.е. апстроф.
eval $ (echo $var _name='$var _значение')
это сработало со мной.

0
27.01.2021, 06:19

Теги

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