Wie erhalte ich einen Variablenwert, wenn der Variablenname als Zeichenfolge gespeichert ist?


141

Wie kann ich einen Bash-Variablenwert abrufen, wenn ich den Variablennamen als Zeichenfolge habe?

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

Kontext:

Ich habe einige AMIs ( Amazon Machine Image ) und möchte einige Instanzen jedes AMI starten. Sobald der Startvorgang abgeschlossen ist, möchte ich jede Instanz entsprechend ihrem AMI-Typ einrichten. Ich möchte nicht viele Skripte oder geheime Schlüssel in einem AMI backen, deshalb habe ich ein verallgemeinertes Startskript vorbereitet und es mit einem öffentlich zugänglichen Link auf S3 gestellt . In rc.local habe ich einen kleinen Code eingefügt, der das Startskript abruft und ausführt. Das ist alles, was ich in den AMIs habe. Anschließend greift jedes AMI auf ein gemeinsames Konfigurationsskript zu, das auf alle AMIs und spezielle Setup-Skripte für jedes AMI anwendbar ist. Diese Skripte sind privat und erfordern eine signierte URL, um darauf zugreifen zu können.

Wenn ich jetzt eine Instanz eines AMI (my_private_ami_1) auslöse, übergebe ich eine signierte URL für eine weitere in S3 präsentierte Datei, die eine signierte URL für alle privaten Skripte in Bezug auf das Schlüssel / Wert-Paar enthält.

config_url="http://s3.amazo.../config?signature"
my_private_ami_1="http://s3.amazo.../ami_1?signature"
...
Wenn das Startskript ausgeführt wird, lädt es die obige Datei herunter und ist sourcees. Dann sucht es nach seinem AMI-Typ und wählt das richtige Setup-Skript für sich aus.

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

Jetzt kann ich einen generischen Code haben, der Instanzen unabhängig von ihren AMI-Typen auslösen kann, und Instanzen können für sich selbst sorgen.

Antworten:


256

Sie können verwenden ${!a}:

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

Dies ist ein Beispiel für eine indirekte Parametererweiterung :

Die Grundform der Parametererweiterung ist ${parameter}. Der Wert von parameterwird ersetzt.

Wenn das erste Zeichen von parameterein Ausrufezeichen (!) Ist , wird eine Ebene der variablen Indirektion eingeführt. Bash verwendet den Wert der aus dem Rest gebildeten Variablen parameterals Namen der Variablen. Diese Variable wird dann erweitert und dieser Wert wird im Rest der Substitution anstelle des Werts von sich parameterselbst verwendet.


4
Das funktioniert bei mir in OSX Bash, aber nicht bei Debian? Auf Debian bekomme ich Bad substitutionFehler.
23inhouse

11
@ 23inhouse Führen Sie Ihr Skript mit aus /bin/sh? Wenn ja, versuchen Sie es /bin/bashstattdessen. Ab Debian Squeeze /bin/shwurde geändert, um ein Symlink für dashstatt zu seinbash . dashunterstützt diese spezielle Syntax nicht und gibt einen Bad substitutionFehler aus.
Phil Ross

8
Gibt es eine Möglichkeit, diese Funktion für einen Variablennamen zu verwenden, der zu einem Array gehört?
Loupax

Arbeitet auf Ubuntu mit Bash
Sergey P. aka Azure

1
@DoronShai Dies ist ein Beispiel für eine indirekte Parametererweiterung, dokumentiert im Bash-Referenzhandbuch unter gnu.org/software/bash/manual/html_node/…
Phil Ross

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

setzt Z auf "foo"

Achten Sie darauf , mit evalda diese accidential Ausfürung von Code durch Werte erlauben kann ${Y}. Dies kann durch Code-Injection zu Schäden führen.

Beispielsweise

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

würde schaffen /tmp/eval-is-evil. Dies könnten rm -rf /natürlich auch einige sein .


rettete meinen Schwanz, ty
raffian

9

Meine Suchwörter geändert und verstanden :).

eval a=\$$a
Vielen Dank für Ihre Zeit.


Seien Sie vorsichtig mit eval, da dies eine versehentliche Auslösung des Codes durch Werte in ermöglichen kann ${Y}. Siehe meinen Zusatz in der Antwort des Benutzers "anon".
Try-Catch-Endlich

Dies ist die einzige funktionierende Antwort. Ironischerweise ist es dein eigenes!
Strg S

8

Für meine Mitbenutzer von zsh besteht der Weg, dasselbe wie die akzeptierte Antwort zu erreichen, darin, Folgendes zu verwenden:

${(P)a}

Dies wird als Ersetzen des Parameternamens bezeichnet

Dadurch wird der Wert des Parameternamens als weiterer Parametername interpretiert, dessen Wert gegebenenfalls verwendet wird. Beachten Sie, dass Flags, die mit einer der gesetzten Befehlsfamilien gesetzt wurden (insbesondere Transformationen), nicht auf den Wert des auf diese Weise verwendeten Namens angewendet werden.

Bei Verwendung mit einem verschachtelten Parameter oder einer Befehlssubstitution wird das Ergebnis auf die gleiche Weise als Parametername verwendet. Wenn Sie beispielsweise 'foo = bar' und 'bar = baz' haben, werden die Zeichenfolgen $ {(P) foo}, $ {(P) $ {foo}} und $ {(P) $ (Echobalken) verwendet. } wird zu 'baz' erweitert.

Wenn die Referenz selbst verschachtelt ist, wird der Ausdruck mit dem Flag so behandelt, als würde er direkt durch den Parameternamen ersetzt. Es ist ein Fehler, wenn diese verschachtelte Ersetzung ein Array mit mehr als einem Wort erzeugt. Wenn beispielsweise 'name = assoc', wobei der Parameter assoc ein assoziatives Array ist, bezieht sich '$ {$ {(P) name} [elt]}' auf das Element des assoziativen tiefgestellten 'elt'.


0

Moderne Shells unterstützen bereits Arrays (und sogar assoziative Arrays). Verwenden Sie sie also bitte und verwenden Sie weniger Eval.

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

Wenn Sie es dann aufrufen möchten, geben Sie $ {array [0]} zurück


würde dies funktionieren, wenn ich den String vom Kommandozeilenargument bekomme (zB als $1)?
Jena

0

Basierend auf der Antwort: 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

Hatte das gleiche Problem mit Arrays. Gehen Sie wie folgt vor, wenn Sie auch Arrays bearbeiten:

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

Dies wird Folgendes ausgeben:

ARRAY=ARRAY_NAME[@]
ARRAY=Val0 Val1 Val2
ARRAY[0]=Val0
ARRAY[1]=Val1
ARRAY[2]=Val2
Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.