Ответ 1
Вы можете построить свое значение var = как строку и оценить его с помощью встроенной команды bash eval
.
Я хочу сделать следующее. Внутри функции мне нужно присвоить значение переменной, имя которой взято из другой переменной. Другими словами:
func() {
#
# Here happens something that ultimately makes $arg="var_name"
#
declare -g ${arg}=5
}
func
echo ${var_name}; # Prints out "5"
Фрагмент кода выше отлично работает в bash 4.2. Однако в bash до 4.2, declare
не имеет опции -g
. Все, что я нашел в google, говорит, что для определения глобальной переменной внутри функции я должен просто использовать синтаксис var=value
, но, к сожалению, var
сам зависит от другой переменной. ${arg}=5
тоже не работает. (Он говорит -bash: var_name=5: command not found
.
Для любопытных причина в том, что эта функция фактически создает глобальные переменные из параметров script, т.е. запуск script --arg1=val
автоматически создает переменную с именем arg1
со значением val
. Сохраняет тонны кода шаблона.
Вы можете построить свое значение var = как строку и оценить его с помощью встроенной команды bash eval
.
declare
внутри функции работает не так, как ожидалось.
Мне нужны глобальные переменные только для чтения, объявленные в функции.
Я пробовал это внутри функции, но это не сработало:
declare -r MY_VAR=1
Но это не сработало. Используя команду readonly
, выполните:
func() {
readonly MY_VAR=1
}
func
echo $MY_VAR
MY_VAR=2
Это приведет к печати 1 и даст ошибку "MY_VAR: переменная readonly" для второго присвоения.
Так как это помечено shell
, важно отметить, что declare
является допустимым ключевым словом только в ограниченном наборе оболочек, поэтому поддерживает ли он -g. Чтобы сделать это в общей оболочке Bourne, вы можете просто использовать eval:
eval ${arg}=5
Использование "eval" (или любого прямого назначения) может дать вам головные боли со специальными символами (или проблемы с инъекцией значений и т.д.).
У меня был большой успех, просто используя "read"
$ function assign_global() {
> local arg="$1"
> IFS="" read -d "" $arg <<<"$2"
>}
$ assign_global MYVAR 23
echo $MYVAR
23
$ assign_global MYVAR "\"'"
"'
Я думаю, вам нужен встроенный printf
с его переключателем -v
:
func() {
printf -v "$var" '5'
}
var=var_name
func
echo "$var_name"
выведет 5
.
Если вы хотите что-то немного менее хакерское, попробуйте использовать export
вместо declare -g
. Теперь он имеет дополнительное преимущество в качестве переменной окружения.
func() {
#
# Here happens something that ultimately makes $arg="var_name"
#
export ${arg}=5
}
func
echo ${var_name}; # Prints out "5"
К сожалению, это все еще не работает для массивов.
Eval будет работать с переменными Array... Мне просто нужно было сделать одиночную цитату локальной переменной Array внутри оператора eval.
Ниже приведена в файле (1-й аргумент) строка за раз, а затем копируется в имя переменной, переданное во второй аргумент get_file.
get_file () {
declare -a Array=();
while read line; do
Array=("${Array[@]}" "($line)")
done < ${1}
eval ${2}='("${Array[@]}")'
unset Array
}
declare -a my_array=();
get_file /etc/myfile.conf my_array
echo ${#my_array[@]}
Возможно, вы могли бы использовать следующие функции для динамического назначения глобальной переменной в bash (< 4.2). Если прошло > 2 аргумента, значение будет типом массива. Например
_set2globals variable_name arg1 [arg2] [arg3] [...]
Источник:
# dynamically set $variable_name($1)=$values($2...) to globals scope
function _set2globals()
{
if (( $# < 2 )); then
printf "$FUNCNAME: expect at least 2 argument, but %d you given.\n" $# >&2
exit 1
fi
local ___pattern_='^[_a-zA-Z][_0-9a-zA-Z]*$'
if [[ ! $1 =~ $___pattern_ ]]; then
printf "$FUNCNAME: invalid variable name: %s.\n" "$1" >&2
exit 1
fi
local __variable__name__=$1
shift
local ___v_
local ___values_=()
while (($# > 0)); do
___v_=\'${1//"'"/"'\''"}\'
___values_=("${___values_[@]}" "$___v_") # push to array
shift
done
eval $__variable__name__=\("${___values_[@]}"\)
}