2013-05-14 21 views
66

Ich bin verwirrt über ein Bash-Skript.Dynamische Variablennamen in Bash

Ich habe den folgenden Code:

function grep_search() { 
    magic_way_to_define_magic_variable_$1=`ls | tail -1` 
    echo $magic_variable_$1 
} 

Ich möchte einen Variablennamen zu erstellen, um der Lage sein, das erste Argument des Befehls enthält, und trägt den Wert von z.B. die letzte Zeile von ls.

So veranschaulichen, was ich will:

$ ls | tail -1 
stack-overflow.txt 

$ grep_search() open_box 
stack-overflow.txt 

Also, wie soll ich definieren/erklären $magic_way_to_define_magic_variable_$1 und wie soll ich es im Skript aufrufen?

Ich habe versucht eval, ${...}, \$${...}, aber ich bin immer noch verwirrt.

+1

$ Nicht. Verwenden Sie ein assoziatives Array, um den Befehlsnamen den Daten zuzuordnen. – chepner

Antwort

74

Verwenden Sie ein assoziatives Array mit Befehlsnamen als Schlüssel.

# Requires bash 4, though 
declare -A magic_variable=() 

function grep_search() { 
    magic_variable[$1]=$(ls | tail -1) 
    echo ${magic_variable[$1]} 
} 

Wenn Sie nicht assoziative Arrays verwenden können (zB müssen Sie bash 3 unterstützt), können Sie declare verwenden dynamische Variablennamen zu erstellen:

declare "magic_variable_$1=$(ls | tail -1)" 

und verwenden indirekte Parameter Erweiterung der für den Zugriff auf Wert.

var="magic_variable_$1" 
echo "${!var}" 
+0

Capital '-A' Option funktionierte nicht für mich. Musste '-a' verwenden. – fent

+2

@DeaDEnD '-a' deklariert ein indiziertes Array, kein assoziatives Array. Wenn das Argument für "grep_search" keine Zahl ist, wird es als Parameter mit einem numerischen Wert behandelt (der Standardwert ist 0, wenn der Parameter nicht festgelegt ist). – chepner

+1

Hmm. Ich verwende bash '4.2.45 (2)' und deklariere es nicht als eine Option 'deklariere: usage: declare [-afFirtx] [-p] [Name [= Wert] ...]'. Es scheint jedoch richtig zu funktionieren. – fent

125

Ich habe in letzter Zeit nach einem besseren Weg gesucht. Assoziative Anordnung klang für mich wie Overkill. Schauen Sie, was ich gefunden habe:

suffix=bzz 
declare prefix_$suffix=mystr 

... und dann ...

varname=prefix_$suffix 
echo ${!varname} 
+9

+1. Sie haben mir gerade meinen Verstand gerettet. Ich habe stundenlang versucht, dies mit zu vielen verschiedenen Lösungen zu erreichen, die beim Googlen gefunden wurden. Das hat wie ein Zauber funktioniert. –

+0

Wenn Sie einen globalen innerhalb einer Funktion deklarieren möchten, können Sie "declare -g" in bash> = 4.2 verwenden. In früheren Bashs kann "readonly" anstelle von "declare" verwendet werden, solange Sie den Wert nicht später ändern möchten. Kann für Konfiguration in Ordnung sein oder was hast du. –

+0

Das hat mir auch sehr geholfen! – gknauth

-1

für varname=$prefix_suffix Format, verwenden Sie einfach:

varname=${prefix}_suffix 
+0

Ich bekomme 'kein Dateiname' Fehler – chovy

3

Dies sollte funktionieren:

function grep_search() { 
    declare magic_variable_$1="$(ls | tail -1)" 
    echo "$(tmpvar=magic_variable_$1 && echo ${!tmpvar})" 
} 
grep_search var # calling grep_search with argument "var" 
1

Wow, das meiste der Syntax ist schrecklich! Hier ist eine Lösung mit etwas einfacher Syntax, wenn Sie benötigen, um indirekt Arrays verweisen:

#!/bin/bash 

foo_1=("fff" "ddd") ; 
foo_2=("ggg" "ccc") ; 

for i in 1 2 ; 
do 
    eval mine=(\${foo_$i[@]}) ; 
    echo ${mine[@]} ; 
done ; 

Für einfachere Anwendungsfälle empfehle ich die syntax described in the Advanced Bash-Scripting Guide.

+1

Die ABS ist jemand berüchtigt dafür, schlechte Praktiken in seinen Beispielen zu zeigen. Bitte denken Sie an das [bash-hackers wiki] (http://wiki.bash-hackers.org/) oder das [Wooledge wiki] (http://mywiki.wooled.org/) - welches direkt auf -Topic-Eintrag [BashFAQ # 6] (http://mywiki.wooledge.org/BashFAQ/006) - stattdessen. –

+0

@CharlesDuffy: Danke, ich werde mir diese Referenzen ansehen. Ich bin mir ziemlich sicher, dass die Syntax hier entweder von mir stammt oder irgendwo von einem anderen Beispiel gehackt wurde. Meine Bezugnahme auf das ABS war für Leute, die nach einem einfacheren Anwendungsfall suchten, z. * nicht * mit dynamischen Variablennamen. Ich dachte, ja, wie verwirrend ist das, wenn jemand nur ein Array referenzieren will und sie diese Antwort finden. – ingyhere

0

Für indizierte Arrays können Sie sie wie so Referenz:

foo=(a b c) 
bar=(d e f) 

for arr_var in 'foo' 'bar'; do 
    declare -a 'arr=("${'"$arr_var"'[@]}")' 
    # do something with $arr 
    echo "\$$arr_var contains:" 
    for char in "${arr[@]}"; do 
     echo "$char" 
    done 
done 

Assoziative Arrays referenziert ähnlich werden können, sondern müssen den -A Schalter auf declare statt -a.

3

Beispiel unten Renditen Wert name_of_var

var=name_of_var 
echo $(eval echo "\$$var")