Comment obtenir une valeur de variable si le nom de la variable est stocké sous forme de chaîne?

142

Comment puis-je récupérer une valeur de variable bash si j'ai le nom de variable sous forme de chaîne?

var1="this is the real value"
a="var1"
Do something to get value of var1 just using variable a.

Le contexte:

J'ai des AMI ( Amazon Machine Image ) et je souhaite lancer quelques instances de chaque AMI. Dès qu'ils ont fini de démarrer, je souhaite configurer chaque instance en fonction de son type d'AMI. Je ne veux pas créer beaucoup de scripts ou de clés secrètes dans une AMI, j'ai donc préparé un script de démarrage généralisé et je l'ai mis sur S3 avec un lien accessible au public. Dans rc.local, j'ai mis un petit morceau de code qui récupère le script de démarrage et l'exécute. C'est tout ce que j'ai dans les AMI. Ensuite, chaque AMI accède à un script de configuration commun qui s'applique à toutes les AMI et à des scripts de configuration spéciaux pour chacune. Ces scripts sont privés et nécessitent une URL signée pour y accéder.

Alors maintenant, lorsque je déclenche une instance d'une AMI (my_private_ami_1), je passe une URL signée pour un autre fichier présenté sur S3 qui contient une URL signée pour tous les scripts privés en termes de paire clé / valeur.

config_url="http://s3.amazo.../config?signature"
my_private_ami_1="http://s3.amazo.../ami_1?signature"
...
Lorsque le script de démarrage s'exécute, il télécharge le fichier ci-dessus et sourcec'est tout. Ensuite, il vérifie son type d'AMI et choisit le script d'installation correct pour lui-même.

ami\_type=GET AMI TYPE #ex: sets ami\_type to my\_private\_ami\_1
setup\_url=GET THE SETUP FILE URL BASED ON AMI\_TYPE # this is where this problem arises

Alors maintenant, je peux avoir un code générique qui peut déclencher des instances indépendamment de leurs types d'AMI et les instances peuvent prendre soin d'elles-mêmes.

bhups
la source

Réponses:

257

Vous pouvez utiliser ${!a}:

var1="this is the real value"
a="var1"
echo "${!a}" # outputs 'this is the real value'

Voici un exemple d' expansion indirecte des paramètres :

La forme de base de l'expansion des paramètres est ${parameter}. La valeur de parameterest substituée.

Si le premier caractère de parameterest un point d'exclamation (!), Il introduit un niveau d'indirection variable. Bash utilise la valeur de la variable formée à partir du reste de parametercomme nom de la variable; cette variable est ensuite développée et cette valeur est utilisée dans le reste de la substitution, plutôt que la valeur d' parameterelle - même.

Phil Ross
la source
4
Cela fonctionne pour moi dans OSX bash, mais pas avec Debian? Sur Debian, j'obtiens une Bad substitutionerreur.
23inhouse
11
@ 23inhouse Exécutez-vous votre script en utilisant /bin/sh? Si tel est le cas, essayez d'utiliser à la /bin/bashplace. À partir de Debian Squeeze, a /bin/shété changé pour devenir un lien symbolique pour dashau lieu debash . dashne prend pas en charge cette syntaxe particulière et affichera une Bad substitutionerreur.
Phil Ross
8
Existe-t-il un moyen de faire fonctionner cela pour un nom de variable qui appartient à un tableau?
Loupax
Fonctionne sur ubuntu avec bash
Sergey P. aka azure
1
@DoronShai Ceci est un exemple d'expansion indirecte des paramètres, documenté dans le manuel de référence de Bash à gnu.org/software/bash/manual/html_node/…
Phil Ross
29
X=foo
Y=X
eval "Z=\$$Y"

définit Z sur "foo"

Faites attention à l' aide evalcar cela peut permettre excution accidential code par des valeurs dans ${Y}. Cela peut causer des dommages par injection de code.

Par exemple

Y="\`touch /tmp/eval-is-evil\`"

créerait /tmp/eval-is-evil. Cela pourrait aussi être certains rm -rf /, bien sûr.

essayer-attraper-enfin
la source
sauvé ma queue, ty
raffian
9

J'ai modifié mes mots clés de recherche et je l'ai compris :).

eval a=\$$a
Merci pour votre temps.

bhups
la source
Faites attention en utilisant eval car cela peut permettre une excution accidentelle de code via des valeurs dans ${Y}. Voir mon ajout dans la réponse de l'utilisateur "anon".
essayez-attrapez-enfin
C'est la seule réponse qui fonctionne. Ironique que ce soit le vôtre!
Ctrl S
8

Pour mes collègues utilisateurs de zsh, le moyen d'accomplir la même chose que la réponse acceptée est d'utiliser:

${(P)a}

C'est ce qu'on appelle le remplacement du nom du paramètre

Cela force la valeur du nom de paramètre à être interprétée comme un autre nom de paramètre, dont la valeur sera utilisée le cas échéant. Notez que les indicateurs définis avec l'une des commandes de la famille de typeset (en particulier les transformations de cas) ne sont pas appliqués à la valeur de nom utilisée de cette manière.

S'il est utilisé avec un paramètre imbriqué ou une substitution de commande, le résultat sera considéré comme un nom de paramètre de la même manière. Par exemple, si vous avez 'foo = bar' et 'bar = baz', les chaînes $ {(P) foo}, $ {(P) $ {foo}} et $ {(P) $ (echo bar) } sera développé en «baz».

De même, si la référence est elle-même imbriquée, l'expression avec l'indicateur est traitée comme si elle était directement remplacée par le nom du paramètre. C'est une erreur si cette substitution imbriquée produit un tableau avec plus d'un mot. Par exemple, si 'name = assoc' où le paramètre assoc est un tableau associatif, alors '$ {$ {(P) name} [elt]}' fait référence à l'élément de l'indicatif associatif 'elt'.

smac89
la source
0

les shells modernes prennent déjà en charge les tableaux (et même les tableaux associatifs). Veuillez donc les utiliser et utiliser moins d'Eval.

var1="this is the real value"
array=("$var1")
# or array[0]="$var1"

puis quand vous voulez l'appeler, echo $ {array [0]}

ghostdog74
la source
cela fonctionnerait-il si j'obtiens la chaîne de l'argument de ligne de commande (par exemple comme $1)?
jena
0

Basé sur la réponse: https://unix.stackexchange.com/a/111627

###############################################################################
# Summary: Returns the value of a variable given it's name as a string.
# Required Positional Argument: 
#   variable_name - The name of the variable to return the value of
# Returns: The value if variable exists; otherwise, empty string ("").
###############################################################################
get_value_of()
{
    variable_name=$1
    variable_value=""
    if set | grep -q "^$variable_name="; then
        eval variable_value="\$$variable_name"
    fi
    echo "$variable_value"
}

test=123
get_value_of test
# 123
test="\$(echo \"something nasty\")"
get_value_of test
# $(echo "something nasty")
VFein
la source
0

J'ai eu le même problème avec les tableaux, voici comment le faire si vous manipulez également des tableaux:

array_name="ARRAY_NAME"
ARRAY_NAME=("Val0" "Val1" "Val2")

ARRAY=$array_name[@]
echo "ARRAY=${ARRAY}"
ARRAY=("${!ARRAY}")
echo "ARRAY=${ARRAY[@]}"
echo "ARRAY[0]=${ARRAY[0]}"
echo "ARRAY[1]=${ARRAY[1]}"
echo "ARRAY[2]=${ARRAY[2]}"

Cela produira:

ARRAY=ARRAY_NAME[@]
ARRAY=Val0 Val1 Val2
ARRAY[0]=Val0
ARRAY[1]=Val1
ARRAY[2]=Val2
Alexandre Hamon
la source