Як отримати значення змінної, якщо ім'я змінної зберігається як рядок?


142

Як я можу отримати значення змінної bash, якщо у мене є назва змінної як рядок?

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

Контекст:

У мене є декілька AMI ( Amazon Machine Image ), і я хочу запустити кілька примірників кожного AMI. Як тільки вони закінчують завантаження, я хочу налаштувати кожен екземпляр відповідно до його типу AMI. Я не хочу запускати багато скриптів або секретних ключів всередині будь-якого AMI, тому я підготував узагальнений сценарій запуску і розмістив його на S3 за загальнодоступним посиланням. У rc.local я поміщаю невеликий фрагмент коду, який отримує сценарій запуску та виконує його. Це все, що я маю в AMI. Тоді кожен AMI отримує доступ до загального сценарію конфігурації, який застосовується до всіх AMI та спеціальних сценаріїв налаштування для кожного. Ці сценарії є приватними та потребують підписаної URL-адреси для доступу до них.

Отже, коли я запускаю екземпляр AMI (my_private_ami_1), я передаю підписану URL-адресу для ще одного файлу, представленого на S3, який містить підписану URL-адресу для всіх приватних сценаріїв з точки зору пари ключ / значення.

config_url="http://s3.amazo.../config?signature"
my_private_ami_1="http://s3.amazo.../ami_1?signature"
...
Коли сценарій запуску запускається, він завантажує вищезазначений файл і sourceйого. Потім він перевіряє свій тип AMI і підбирає правильний сценарій налаштування для себе.

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

Тож тепер у мене може бути загальний код, який може запускати екземпляри незалежно від їх типів AMI, а екземпляри можуть піклуватися про себе.

Відповіді:


257

Ви можете використовувати ${!a}:

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

Це приклад непрямого розширення параметрів :

Основна форма розширення параметра - це ${parameter}. Значення parameterзаміщене.

Якщо перший символ символу parameter- знак оклику (!), Він вводить рівень змінної непрямості. Bash використовує значення змінної, утвореної від решти, parameterяк ім'я змінної; Потім ця змінна розширюється, і це значення використовується в іншому місці заміщення, а не в значенні самої parameterсебе.


4
Це працює для мене в базі OSX, але не debian? На debian я отримую Bad substitutionпомилку.
23inhouse

11
@ 23inhouse Ви використовуєте сценарій, використовуючи /bin/sh? Якщо так, спробуйте використовувати /bin/bashзамість цього. Від Debian Squeeze далі /bin/shбуло замінено на символьне посилання dashзамістьbash . dashне підтримує конкретний синтаксис і видасть Bad substitutionпомилку.
Філ Росс

8
Чи є спосіб зробити цю роботу для імені змінної, що належить до масиву?
Лупакс

Працює на ubuntu з bash
Сергій П. aka azure

1
@DoronShai Це приклад непрямого розширення параметрів, задокументований у Довідковому посібнику Баша за
Філ Росс,

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

задає Z на "foo"

Будьте обережні, використовуючи, evalоскільки це може дозволити повернення коду через значення в${Y} . Це може заподіяти шкоду через введення коду.

Наприклад

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

створив би /tmp/eval-is-evil. Це rm -rf /, звичайно, може бути і деяким .


врятував мій хвіст, ty
raffian

9

Змінив мої ключові слова пошуку і зрозумів :).

eval a=\$$a
Дякую за ваш час.


Будьте обережні, використовуючи eval, оскільки це може дозволити повернення коду через значення в ${Y}. Дивіться моє доповнення у відповіді користувача "anon".
пробуй-нарешті

Це єдина дієва відповідь. Іронічно, що це ваше власне!
Ctrl S

8

Для моїх колег користувачів zsh спосіб досягнення того ж самого, що і прийнята відповідь, - використовувати:

${(P)a}

Він називається заміною імені параметра

Це змушує значення імені параметра інтерпретувати як подальше ім'я параметра, значення якого буде використовуватися, коли це доречно. Зауважте, що прапори, встановлені з одним із команд сімейства наборів команд (зокрема перетворення випадків), не застосовуються до значення імені, використовуваного таким чином.

Якщо використовується з вкладеним параметром або підстановкою команд, результат цього буде взято як ім’я параметра аналогічно. Наприклад, якщо у вас є 'foo = bar' і 'bar = baz', рядки $ {(P) foo}, $ {(P) $ {foo}} і $ {(P) $ (смуга відлуння) } буде розширено до 'baz'.

Так само, якщо посилання є самою вкладеною, вираз із прапором трактується так, як ніби він був безпосередньо замінений назвою параметра. Це помилка, якщо ця вкладена підміна створює масив з більш ніж одним словом. Наприклад, якщо 'name = assoc', де параметр assoc є асоціативним масивом, то '$ {$ {(P) ім'я} [elt]}' посилається на елемент асоційованого підписаного 'elt'.


0

сучасні оболонки вже підтримують масиви (і навіть асоціативні масиви). Тому будь ласка, використовуйте їх, а використовуйте менше eval.

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

тоді, коли ви хочете зателефонувати, відлучіть $ {array [0]}


чи буде це працювати, якщо я отримаю рядок з аргументу командного рядка (наприклад, як $1)?
Jena

0

Виходячи з відповіді: 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

У вас була така ж проблема з масивами, ось як це зробити, якщо ви також маніпулюєте масивами:

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

Це виведе:

ARRAY=ARRAY_NAME[@]
ARRAY=Val0 Val1 Val2
ARRAY[0]=Val0
ARRAY[1]=Val1
ARRAY[2]=Val2
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.