Jak uzyskać wartość zmiennej, jeśli nazwa zmiennej jest przechowywana jako ciąg?


142

Jak mogę pobrać wartość zmiennej bash, jeśli mam nazwę zmiennej jako ciąg?

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

Kontekst:

Mam kilka AMI ( Amazon Machine Image ) i chcę odpalić kilka instancji każdego AMI. Gdy tylko zakończą ładowanie, chcę skonfigurować każdą instancję zgodnie z jej typem AMI. Nie chcę piec wielu skryptów ani tajnych kluczy w żadnym AMI, więc przygotowałem uogólniony skrypt startowy i umieściłem go na S3 z publicznie dostępnym linkiem. W rc.local umieściłem mały fragment kodu, który pobiera skrypt startowy i wykonuje go. To wszystko, co mam w AMI. Następnie każdy AMI uzyskuje dostęp do wspólnego skryptu konfiguracyjnego, który ma zastosowanie do wszystkich AMI i specjalnych skryptów instalacyjnych dla każdego. Te skrypty są prywatne i wymagają podpisanego adresu URL, aby uzyskać do nich dostęp.

Tak więc teraz, kiedy uruchamiam instancję AMI (my_private_ami_1), przekazuję podpisany adres URL dla jeszcze jednego pliku prezentowanego na S3, który zawiera podpisany adres URL dla wszystkich prywatnych skryptów pod względem pary klucz / wartość.

config_url="http://s3.amazo.../config?signature"
my_private_ami_1="http://s3.amazo.../ami_1?signature"
...
Po uruchomieniu skryptu startowego pobiera powyższy plik i sourceto wszystko. Następnie sprawdza typ AMI i wybiera dla siebie poprawny skrypt instalacyjny.

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

Więc teraz mogę mieć ogólny kod, który może uruchamiać instancje niezależnie od ich typów AMI, a instancje mogą same o siebie zadbać.

Odpowiedzi:


257

Możesz użyć ${!a}:

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

Oto przykład pośredniej ekspansji parametrów :

Podstawową formą ekspansji parametrów jest ${parameter}. Wartość parameterjest podstawiana.

Jeśli pierwszy znak parameterjest wykrzyknikiem (!), Wprowadza poziom zmiennej pośredniej. Bash używa wartości zmiennej utworzonej z reszty parameterjako nazwy zmiennej; ta zmienna jest następnie interpretowana i ta wartość jest używana w pozostałej części podstawiania, a nie jako wartość parametersama w sobie.


4
To działa dla mnie w OSX bash, ale nie w Debianie? W debianie pojawia się Bad substitutionbłąd.
domu

11
@ 23inhouse Czy używasz swojego skryptu /bin/sh? Jeśli tak, spróbuj użyć /bin/bashzamiast tego. Począwszy od Debian Squeeze, /bin/shzostał zmieniony na dowiązanie symboliczne dashzamiastbash . dashnie obsługuje tej konkretnej składni i wyświetli Bad substitutionbłąd.
Phil Ross

8
Czy istnieje sposób, aby to zadziałało dla nazwy zmiennej, która należy do tablicy?
Loupax

Działa na ubuntu z bashem
Sergey P. aka azure

1
@DoronShai To jest przykład pośredniego rozwijania parametrów, udokumentowany w podręczniku Bash Reference Manual na gnu.org/software/bash/manual/html_node/ ...
Phil Ross

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

ustawia Z na „foo”

Uważaj przy używaniu, evalponieważ może to pozwolić na przypadkowe wykluczenie kodu przez wartości w ${Y}. Może to spowodować szkody przez wstrzyknięcie kodu.

Na przykład

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

stworzy /tmp/eval-is-evil. To też rm -rf /oczywiście może być trochę .


uratował mój ogon, ty
rafian

9

Zmodyfikowałem słowa kluczowe wyszukiwania i rozumiem :).

eval a=\$$a
Dziękuję za Twój czas.


Uważaj, używając eval, ponieważ może to pozwolić na przypadkowe wykluczenie kodu przez wartości w ${Y}. Zobacz mój dodatek w odpowiedzi użytkownika „anon”.
spróbuj złapać wreszcie

To jedyna działająca odpowiedź. Jak na ironię, to twój własny!
Ctrl S

8

Dla innych użytkowników zsh sposobem na osiągnięcie tego samego, co zaakceptowana odpowiedź, jest użycie:

${(P)a}

Nazywa się to zastępowaniem nazwy parametru

Wymusza to interpretację wartości nazwy parametru jako kolejnej nazwy parametru, której wartość będzie używana w odpowiednich przypadkach. Zwróć uwagę, że flagi ustawione za pomocą jednej z rodziny poleceń (w szczególności transformacje) nie są stosowane do wartości nazwy używanej w ten sposób.

W przypadku użycia z zagnieżdżonym parametrem lub podstawieniem polecenia, wynik tego zostanie potraktowany jako nazwa parametru w ten sam sposób. Na przykład, jeśli masz „foo = bar” i „bar = baz”, ciągi $ {(P) foo}, $ {(P) $ {foo}} i $ {(P) $ (echo bar) } zostanie rozwinięty do 'baz'.

Podobnie, jeśli samo odwołanie jest zagnieżdżone, wyrażenie z flagą jest traktowane tak, jakby zostało bezpośrednio zastąpione nazwą parametru. Jest błędem, jeśli to zagnieżdżone podstawienie tworzy tablicę zawierającą więcej niż jedno słowo. Na przykład, jeśli „name = assoc”, gdzie parametr assoc jest tablicą asocjacyjną, to „$ {$ {(P) nazwa} [elt]}” odnosi się do elementu asocjacyjnego z indeksem „elt”.


0

Nowoczesne powłoki już obsługują tablice (a nawet tablice asocjacyjne). Więc proszę, używaj ich i używaj mniej wartości eval.

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

wtedy kiedy chcesz to wywołać, echo $ {tablica [0]}


czy to zadziała, jeśli otrzymam ciąg z argumentu wiersza poleceń (np. as $1)?
jena

0

Na podstawie odpowiedzi: 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

Miał ten sam problem z tablicami, oto jak to zrobić, jeśli manipulujesz również tablicami:

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

Spowoduje to:

ARRAY=ARRAY_NAME[@]
ARRAY=Val0 Val1 Val2
ARRAY[0]=Val0
ARRAY[1]=Val1
ARRAY[2]=Val2
Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.