Лучше как:
cd top &&
for i in */; do (cd -- "$i" && sha1sum -- * > sha1sum); done
Если вы это сделаете:
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
вызывает псевдоним и выполняется определение переменной, сохраненное в псевдониме, после чего новый псевдоним
немедленно удаляется из хеш-таблицы.
Не используйте для этого 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")"
Хороший способ работы с 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
ранее было объявлено как скаляр , массив или ассоциативный массив .
используйте мертвые кавычки, т.е. апстроф.
eval $ (echo $var _name='$var _значение')
это сработало со мной.