Come ottenere un valore variabile se il nome della variabile è archiviato come stringa?


142

Come posso recuperare un valore della variabile bash se ho il nome della variabile come stringa?

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

Contesto:

Ho alcune AMI ( Amazon Machine Image ) e voglio avviare alcune istanze di ciascuna AMI. Non appena termina l'avvio, voglio impostare ciascuna istanza in base al suo tipo AMI. Non voglio creare molti script o chiavi segrete all'interno di qualsiasi AMI, quindi ho preparato uno script di avvio generalizzato e l'ho messo su S3 con un link accessibile pubblicamente. In rc.local ho messo un piccolo pezzo di codice che recupera lo script di avvio ed lo esegue. Questo è tutto ciò che ho nelle AMI. Quindi ogni AMI accede a uno script di configurazione comune che è applicabile a tutte le AMI e script di installazione speciali per ciascuno. Questi script sono privati ​​e richiedono un URL firmato per accedervi.

Quindi ora, quando eseguo un'istanza di un AMI (my_private_ami_1), passo un URL firmato per un altro file presentato su S3 che contiene un URL firmato per tutti gli script privati ​​in termini di coppia chiave / valore.

config_url="http://s3.amazo.../config?signature"
my_private_ami_1="http://s3.amazo.../ami_1?signature"
...
Quando viene eseguito lo script di avvio, scarica il file sopra e sourcelo è. Quindi controlla il suo tipo di AMI e seleziona da solo lo script di installazione corretto.

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

Quindi ora posso avere un codice generico che può generare istanze indipendentemente dai loro tipi di AMI e le istanze possono prendersi cura di se stesse.

Risposte:


257

Puoi usare ${!a}:

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

Questo è un esempio di espansione indiretta dei parametri :

La forma base dell'espansione dei parametri è ${parameter}. Il valore di parameterè sostituito.

Se il primo carattere di parameterè un punto esclamativo (!), Introduce un livello di indiretta variabile. Bash utilizza il valore della variabile formata dal resto di parametercome nome della variabile; questa variabile viene quindi espansa e quel valore viene utilizzato nel resto della sostituzione, piuttosto che il valore di parameterse stesso.


4
Questo funziona per me in OSX bash, ma non debian? Su debian ricevo un Bad substitutionerrore.
23

11
@ 23inhouse Stai eseguendo il tuo script utilizzando /bin/sh? In tal caso, prova a utilizzare /bin/bashinvece. Da Debian Squeeze in poi, è /bin/shstato modificato per essere un collegamento simbolico dashanzichébash . dashnon supporta questa sintassi particolare e genererà un Bad substitutionerrore.
Phil Ross,

8
C'è un modo per farlo funzionare per un nome di variabile che appartiene a un array?
Loupax,

Funziona su Ubuntu con bash
Sergey P. aka azure,

1
@DoronShai Questo è un esempio di espansione indiretta dei parametri, documentata nel Manuale di riferimento di Bash su gnu.org/software/bash/manual/html_node/…
Phil Ross,

29
X=foo
Y=X
eval "Z=\$$Y"

imposta Z su "pippo"

Prestare attenzione utilizzando in evalquanto ciò può consentire l'escissione accidentale del codice attraverso i valori in ${Y}. Ciò può causare danni attraverso l'iniezione di codice.

Per esempio

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

creerebbe /tmp/eval-is-evil. Questo potrebbe anche essere alcuni rm -rf /, ovviamente.


mi ha salvato la coda,
Ty

9

Modificate le mie parole chiave di ricerca e ho capito :).

eval a=\$$a
Grazie per il tuo tempo.


Prestare attenzione utilizzando eval poiché ciò può consentire l'escissione accidentale del codice attraverso i valori in ${Y}. Vedi la mia aggiunta nella risposta dell'utente "anon".
try-catch-finally

Questa è l'unica risposta funzionante. Ironico che è tuo!
Ctrl S

8

Per i miei colleghi utenti zsh, il modo per ottenere lo stesso risultato della risposta accettata è utilizzare:

${(P)a}

Si chiama Sostituzione nome parametro

Ciò impone che il valore del nome del parametro venga interpretato come un ulteriore nome del parametro, il cui valore verrà utilizzato dove appropriato. Si noti che i flag impostati con una delle famiglie di comandi del set (in particolare trasformazioni di casi) non vengono applicati al valore del nome utilizzato in questo modo.

Se utilizzato con un parametro nidificato o una sostituzione di comando, il risultato verrà preso come nome di parametro nello stesso modo. Ad esempio, se hai "foo = bar" e "bar = baz", le stringhe $ {(P) foo}, $ {(P) $ {foo}} e $ {(P) $ (barra dell'eco) } verrà espanso in "baz".

Allo stesso modo, se il riferimento è nidificato, l'espressione con il flag viene trattata come se fosse sostituita direttamente dal nome del parametro. È un errore se questa sostituzione nidificata produce un array con più di una parola. Ad esempio, se 'nome = assoc' in cui il parametro assoc è un array associativo, allora '$ {$ {(P) name} [elt]}' si riferisce all'elemento dell'associato in abbonamento 'elt'.


0

le shell moderne supportano già array (e persino array associativi). Quindi, per favore, usali e usa meno di valutazione.

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

poi quando vuoi chiamarlo, echo $ {array [0]}


funzionerebbe se ottengo la stringa dall'argomento della riga di comando (es. come $1)?
Jena,

0

Sulla base della risposta: 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")

0

Ha avuto lo stesso problema con le matrici, ecco come farlo se stai manipolando anche le matrici:

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]}"

Questo produrrà:

ARRAY=ARRAY_NAME[@]
ARRAY=Val0 Val1 Val2
ARRAY[0]=Val0
ARRAY[1]=Val1
ARRAY[2]=Val2
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.