Déclarer une variable globale dans une fonction

ce que je veux faire, c'est suivre. L'intérieur d'une fonction, j'ai besoin d'assigner une valeur à une variable, dont le nom est pris d'une autre variable. En d'autres termes:

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

func

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

l'extrait de code ci-dessus fonctionne très bien dans bash 4.2. Cependant, à bash Avant 4.2,declare ne pas -g option. Tout ce que j'ai trouvé chez google dit que pour définir la variable globale à l'intérieur d'une fonction, je devrais juste utiliser le var=value la syntaxe, mais malheureusement var lui-même dépend d'un autre variable. ${arg}=5 ne fonctionne pas non plus. (Il est dit -bash: var_name=5: command not found.

pour les curieux, la raison de tout cela est que cette fonction crée en fait des variables globales à partir des paramètres du script, c'est-à-dire en exécutant script --arg1=val crée automatiquement la variable named arg1 valeur val. Économise des tonnes de code boilerplate.

20
demandé sur codeforester 2012-03-26 15:42:39

9 réponses

Vous pouvez construire votre var=valeur comme une chaîne et l'évaluer en utilisant la commande bash builtin eval.

2
répondu minopret 2012-03-26 17:14:01

declare à l'intérieur d'une fonction ne fonctionne pas comme prévu. J'avais besoin de variables globales en lecture seule déclarées dans une fonction. J'ai essayé ce à l'intérieur d'une fonction, mais il ne fonctionne pas:

declare -r MY_VAR=1

Mais cela ne fonctionne pas. À l'aide de la readonly commande:

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

ceci affichera 1 et donnera l'erreur "MY_VAR: readonly variable" pour la seconde tâche.

14
répondu kipibenkipod 2012-08-28 13:03:53

Puisque c'est marqué shell, il est important de noter que declare est un mot-clé valide seulement dans un ensemble limité de shells, donc si elle supporte -g est discutable. Pour faire ce genre de chose dans un shell Bourne Générique, vous pouvez simplement utiliser eval:

eval ${arg}=5
7
répondu William Pursell 2012-03-26 12:51:57

je pense que vous avez besoin de l' printf construire avec son -v switch:

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

sortie 5.

4
répondu gniourf_gniourf 2014-11-11 19:57:14

utiliser "eval" (ou n'importe quelle assignation directe) peut vous donner des maux de tête avec des caractères spéciaux (ou des problèmes avec l'injection de valeur etc).

j'ai eu beaucoup de succès en utilisant simplement sur "lire"

$ function assign_global() {
>   local arg=""
>   IFS="" read -d "" $arg <<<""
>}
$ assign_global MYVAR 23
echo $MYVAR
23
$ assign_global MYVAR "\"'"
"'
3
répondu Beorn Harris 2012-04-20 10:40:36

Si vous voulez quelque chose d'un peu moins hackish, essayez d'utiliser export à la place de declare -g. Il a l'avantage d'être une variable d'environnement maintenant.

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

func

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

Malheureusement, cela ne fonctionne toujours pas pour les tableaux.

3
répondu Zach 2016-10-07 18:50:20

dans Bash pour déclarer des variables de tableaux à l'intérieur d'une définition de fonction, vous pouvez utiliser le local commande en combinaison avec l' eval commande comme dans l'exemple suivant:

#!/bin/bash
function test
{
    local -g 
    local array=( AA BB 'C C' DD)
    eval ='("${array[@]}")'
}
test VAR
echo VAR=${VAR[@]:1:2}

la sortie sera:

$./test.sh
VAR=BB C C

fonctionne avec: GNU bash, Version 4.4.18

1
répondu tomy 2018-02-15 12:12:47

Eval fonctionnera avec des variables de tableau...J'ai juste dû citer la variable Local Array à l'intérieur de la déclaration eval.

ce qui suit lit dans un fichier (1ère arg) une ligne à la fois et le copie ensuite au nom de la variable passé au 2ème arg du get_file.

get_file () {
  declare -a Array=();
  while read line; do
    Array=("${Array[@]}" "($line)")
  done < 
  eval ='("${Array[@]}")'
  unset Array
}

declare -a my_array=();
get_file /etc/myfile.conf my_array
echo ${#my_array[@]}
0
répondu ASG 2014-11-11 19:10:40

peut-être que vous pourriez utiliser les fonctions suivantes pour assigner dynamiquement votre variable globale dans bash(< 4.2). Si > 2 args passés, alors la valeur sera de type array. E. G

_set2globals variable_name arg1 [arg2] [arg3] [...]

Source:

# dynamically set $variable_name()=$values(...) 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 [[ !  =~ $___pattern_ ]]; then
        printf "$FUNCNAME: invalid variable name: %s.\n" "" >&2
        exit 1
    fi
    local __variable__name__=
    shift
    local ___v_
    local ___values_=()
    while (($# > 0)); do
        ___v_=\'${1//"'"/"'\''"}\'
        ___values_=("${___values_[@]}" "$___v_") # push to array
        shift
    done

    eval $__variable__name__=\("${___values_[@]}"\)
}
0
répondu Ekeyme Mo 2016-03-24 08:06:00