Подтвердить что ты не робот

Bash: объявление глобальной переменной внутри функции

Я хочу сделать следующее. Внутри функции мне нужно присвоить значение переменной, имя которой взято из другой переменной. Другими словами:

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. Сохраняет тонны кода шаблона.

4b9b3361

Ответ 1

Вы можете построить свое значение var = как строку и оценить его с помощью встроенной команды bash eval.

Ответ 2

declare внутри функции работает не так, как ожидалось. Мне нужны глобальные переменные только для чтения, объявленные в функции. Я пробовал это внутри функции, но это не сработало:

declare -r MY_VAR=1

Но это не сработало. Используя команду readonly, выполните:

func() {
    readonly MY_VAR=1
}
func
echo $MY_VAR
MY_VAR=2

Это приведет к печати 1 и даст ошибку "MY_VAR: переменная readonly" для второго присвоения.

Ответ 3

Так как это помечено shell, важно отметить, что declare является допустимым ключевым словом только в ограниченном наборе оболочек, поэтому поддерживает ли он -g. Чтобы сделать это в общей оболочке Bourne, вы можете просто использовать eval:

eval ${arg}=5

Ответ 4

Использование "eval" (или любого прямого назначения) может дать вам головные боли со специальными символами (или проблемы с инъекцией значений и т.д.).

У меня был большой успех, просто используя "read"

$ function assign_global() {
>   local arg="$1"
>   IFS="" read -d "" $arg <<<"$2"
>}
$ assign_global MYVAR 23
echo $MYVAR
23
$ assign_global MYVAR "\"'"
"'

Ответ 5

Я думаю, вам нужен встроенный printf с его переключателем -v:

func() {
    printf -v "$var" '5'
}
var=var_name
func
echo "$var_name"

выведет 5.

Ответ 6

Если вы хотите что-то немного менее хакерское, попробуйте использовать export вместо declare -g. Теперь он имеет дополнительное преимущество в качестве переменной окружения.

func() {  
#  
# Here happens something that ultimately makes $arg="var_name"
# 
export ${arg}=5
}

func

echo ${var_name}; # Prints out "5"

К сожалению, это все еще не работает для массивов.

Ответ 7

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[@]}

Ответ 8

Возможно, вы могли бы использовать следующие функции для динамического назначения глобальной переменной в 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_[@]}"\)
}