web-dev-qa-db-fra.com

Déclarer une variable globale dans une fonction

Ce que je veux faire, c'est suivre. Dans une fonction, je dois attribuer une valeur à une variable dont le nom provient 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 parfaitement dans bash 4.2. Cependant, dans les versions antérieures à 4.2, declare ne dispose pas de l'option -g. Tout ce que j'ai trouvé sur Google indique que pour définir la variable globale dans une fonction, je devrais simplement utiliser la syntaxe var=value, mais malheureusement, var dépend lui-même d'une autre variable. ${arg}=5 ne fonctionne pas non plus. (On dit -bash: var_name=5: command not found.

Pour les curieux, la raison en est que cette fonction crée en fait des variables globales à partir des paramètres de script. Par exemple, l'exécution de script --arg1=val crée automatiquement la variable nommée arg1 avec la valeur val. Enregistre des tonnes de code standard.

20
Leonid99

Vous pouvez construire votre var = valeur sous forme de chaîne et l'évaluer à l'aide de la commande intégrée bash eval.

2
minopret

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é ceci à l'intérieur d'une fonction mais cela n'a pas fonctionné:

declare -r MY_VAR=1

Mais cela n'a pas fonctionné. L'utilisation de la commande readonly a:

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

Ceci affichera 1 et donnera l’erreur "MY_VAR: variable en lecture seule" pour la deuxième affectation.

14
kipibenkipod

Etant donné que cette balise porte la balise Shell, il est important de noter que declare est un mot clé valide uniquement dans un ensemble limité de shells. Par conséquent, s'il prend en charge -g est sans objet. Pour faire ce genre de chose dans un Bourne Shell générique, vous pouvez simplement utiliser eval:

eval ${arg}=5
7
William Pursell

Je pense que vous avez besoin de la variable printf avec son commutateur -v:

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

affichera 5.

6
gniourf_gniourf

L'utilisation de "eval" (ou de toute affectation directe) peut vous donner des maux de tête avec des caractères spéciaux (ou des problèmes d'injection de valeur, etc.).

J'ai eu beaucoup de succès en utilisant simplement "read"

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

Si vous voulez quelque chose d'un peu moins hackish, essayez d'utiliser export à la place de declare -g. Il a l'avantage supplémentaire 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
Zach

Dans Bash pour déclarer des variables de tableau dans une définition de fonction, vous pouvez utiliser la commande local en combinaison avec la commande eval comme dans l'exemple suivant:

#!/bin/bash
function test
{
    local -g $1
    local array=( AA BB 'C C' DD)
    eval ${1}='("${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
tomy

Eval fonctionnera avec les variables de tableau ... Il me suffisait de ne citer que la variable de tableau locale à l'intérieur de l'instruction eval.

Le texte ci-dessous lit dans un fichier (1er argument) une ligne à la fois, puis le copie dans le nom de variable transmis au deuxième argument du 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[@]}

0
ASG

Vous pourriez peut-être utiliser les fonctions suivantes pour affecter dynamiquement votre variable globale dans bash (<4.2). Si> 2 arguments sont passés, la valeur sera le type de tableau . E.G

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

La source:

# 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_[@]}"\)
}
0
Ekeyme Mo