Ist es möglich, den Inhalt einer Variablen mit einem Shell-Skript zu drucken? (indirekte Referenzierung)

13

Nehmen wir an, ich habe die folgenden Variablen deklariert:

$ var='$test'
$ test="my string"

Wenn ich deren Inhalt drucke, sehe ich Folgendes:

$ echo $var
$test

$ echo $test
my string

Ich möchte einen Weg finden, um den Inhalt des Inhalts von $var(der der Inhalt von ist $test) zu drucken . Also habe ich folgendes versucht:

$ echo $(echo $var)
$test

Aber hier ist das Ergebnis $testund nicht "my string"... Ist es möglich, den Inhalt von Variablen mit bash zu drucken?

Rafael Muynarsk
quelle
Könnten Sie bearbeiten Ihre Post zu sagen , was Sie verwenden Schale, oder welche Portabilität Anforderungen , die Sie haben?
Michael Homer
@MichaelHomer Sicher, aber wie genau kann ich diese Informationen überprüfen?
Rafael Muynarsk
Es ist mehr etwas, das Sie wählen, als etwas zu überprüfen. Führen Sie Ihre Skripte beispielsweise mit ashoder bashoder cshoder dash... oder zshoder POSIX aus sh, oder müssen Sie systemübergreifend arbeiten?
Michael Homer
@MichaelHomer Ah, ich verstehe ... ich benutze Bash. Ich werde nur die letzte Frage ändern und dann einen neuen Tag einfügen.
Rafael Muynarsk

Antworten:

21

Sie können dies mit der indirekten Variablenerweiterung von bash erreichen (solange es in Ordnung ist, die $Referenzvariable wegzulassen):

$ var=test
$ test="my string"
$ echo "$var"
test
$ echo "${!var}"
my string

3.5.3 Shell-Parametererweiterung

Jesse_b
quelle
10

Für den Fall, dass der in enthaltene Variablenname varmit einem Präfix versehen ist $, können Sie Folgendes verwenden eval:

$ var='$test'
$ test="my string"
$ eval echo $var
my string

Was geschieht hier:

  • Bash wird $varauf den Wert erweitert $testund erzeugt einen eval echo $testBefehl.
  • evalwertet den echo $testAusdruck aus und erzeugt ein gewünschtes Ergebnis.

Beachten Sie, dass die Verwendung evalim Allgemeinen gefährlich sein kann (je nachdem, was darin aufbewahrt wird var). Vermeiden Sie es daher lieber. Die indirekte Erweiterungsfunktion ist für Ihren Fall besser (Sie müssen jedoch die $Anmeldung entfernen $test).

Danila Kiver
quelle
Klar, das ist ein Fehler. Der ursprüngliche Beitrag enthält einfache Anführungszeichen. Fest.
Danila Kiver
4
Ich empfehle immer, Variablenverweise in doppelte Anführungszeichen zu setzen (um Probleme durch unerwartete Wortteilung und Platzhaltererweiterung zu vermeiden). Mit evalbenötigen Sie zwei Ebenen mit doppelten Anführungszeichen eval echo "\"$var\"". Wohlgemerkt, dies ändert nichts an den anderen Gefahren, evaldie Sie bei der Verwendung genannt haben .
Gordon Davisson
9

Ähnlich wie die Antwort von Jesse_b , jedoch unter Verwendung einer Namensreferenzvariablen anstelle einer Variablenumleitung (erfordert bash4.3+):

$ declare -n var=test
$ test="my string"
$ echo "$var"
my string

Die Namensreferenzvariable varenthält den Namen der Variablen, auf die sie verweist. Wenn die Variable dereferenziert wird als$var , wird der Wert dieser anderen Variablen zurückgegeben.

bash löst Namensreferenzen rekursiv auf:

$ declare -n var1=var2
$ declare -n var2=test
$ test="hello world"
$ echo "$var1"
hello world

Der Vollständigkeit bashhalber ist die Verwendung eines assoziativen Arrays (in 4.0+) auch eine Möglichkeit, dies zu lösen, abhängig von den Anforderungen:

$ declare -A strings
$ strings[test]="my string"
$ var=test
$ echo "${strings[$var]}"
my string

Dies bietet eine flexiblere Möglichkeit, über einen Schlüssel oder Namen, der dynamisch bestimmt werden kann, auf mehr als einen Wert zuzugreifen. Dies ist möglicherweise vorzuziehen, wenn Sie alle Werte einer bestimmten Kategorie in einem einzigen Array erfassen möchten, aber dennoch über einen bestimmten Schlüssel darauf zugreifen können (z. B. über ID zugreifbare Namen oder über Zweck zugreifbare Pfadnamen usw.), da dies nicht zu einer Verschmutzung führt der variable Namespace des Skripts.

Kusalananda
quelle
3

Mit zsh:

$ var='$test'
$ test='*'
$ printf '%s\n' ${(e)var}
*

Mit jeder Bourne-ähnlichen Muschel

$ eval 'printf "%s\n" "'"$var"'"'
*

Denken Sie daran, dass in diesen Shells variable Erweiterungen in Anführungszeichen gesetzt werden müssen, um Split + Glob ( zsheine Ausnahme) zu vermeiden. Sie echokönnen nicht für beliebige Daten verwendet werden.

Da bei beiden (e)und evales eine Shell-Code-Auswertung gibt, ist es wichtig, den Inhalt von$var Aufenthalts in Ihrer Kontrolle , da sonst die einen beliebigen Befehl Injection - Schwachstelle sein kann (gleiche mit ${!var}Ansätzen).

Stéphane Chazelas
quelle