Como obter um valor de variável se o nome da variável é armazenado como string?

142

Como recuperar um valor de variável bash se eu tiver o nome da variável como string?

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

Contexto:

Tenho algumas AMI's ( Amazon Machine Image ) e quero iniciar algumas instâncias de cada AMI. Assim que eles terminarem de inicializar, desejo configurar cada instância de acordo com seu tipo de AMI. Como não quero criar muitos scripts ou chaves secretas dentro de qualquer AMI, preparei um script de inicialização generalizado e o coloquei no S3 com um link acessível ao público. No rc.local, coloquei um pequeno pedaço de código que busca o script de inicialização e o executa. Isso é tudo o que tenho nas AMIs. Em seguida, cada AMI acessa um script de configuração comum que é aplicável a todas as AMIs e scripts de configuração especiais para cada um. Esses scripts são particulares e requerem uma URL assinada para acessá-los.

Portanto, agora, quando aciono uma instância de uma AMI (my_private_ami_1), passo uma URL assinada para mais um arquivo apresentado no S3 que contém a URL assinada para todos os scripts privados em termos de par de chave / valor.

config_url="http://s3.amazo.../config?signature"
my_private_ami_1="http://s3.amazo.../ami_1?signature"
...
Quando o script de inicialização é executado, ele baixa o arquivo acima e sourceé ele. Em seguida, verifica o seu tipo de AMI e escolhe o script de instalação correto.

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

Então agora eu posso ter um código genérico que pode disparar instâncias, independentemente de seus tipos de AMI, e as instâncias podem cuidar de si mesmas.

bhups
fonte

Respostas:

257

Você pode usar ${!a}:

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

Este é um exemplo de expansão indireta de parâmetros :

A forma básica de expansão de parâmetro é ${parameter}. O valor de parameteré substituído.

Se o primeiro caractere de parameterfor um ponto de exclamação (!), Ele introduzirá um nível de variável indireta. O Bash usa o valor da variável formada a partir do restante parametercomo o nome da variável; essa variável é então expandida e esse valor é usado no restante da substituição, em vez do valor em parametersi.

Phil Ross
fonte
4
Isso funciona para mim no OSX bash, mas não no debian? No debian, recebo Bad substitutionerro.
238 de 23inhouse
11
@ 23inhouse Você está executando seu script /bin/sh? Nesse caso, tente usar /bin/bash. Do Debian Squeeze em diante, /bin/shfoi alterado para ser um link simbólico, em dashvez debash . dashnão suporta esta sintaxe específica e gera um Bad substitutionerro.
Phil Ross
8
Existe uma maneira de fazer isso funcionar para um nome de variável que pertence a uma matriz?
Loupax 15/01
Funciona no ubuntu com bash
Sergey P. aka azure
1
@DoronShai Este é um exemplo de expansão indireta de parâmetros, documentada no Manual de Referência do Bash em gnu.org/software/bash/manual/html_node/…
Phil Ross
29
X=foo
Y=X
eval "Z=\$$Y"

define Z como "foo"

Tome cuidado ao usar, evalpois isso pode permitir a extração acidental de código por meio de valores em ${Y}. Isso pode causar danos através da injeção de código.

Por exemplo

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

criaria /tmp/eval-is-evil. Isso também pode ser um pouco rm -rf /, é claro.

finalmente tente
fonte
salvou meu rabo, ty
raffian
9

Modificado minhas palavras-chave de pesquisa e Entendi :).

eval a=\$$a
Obrigado pelo seu tempo.

bhups
fonte
Tome cuidado ao usar eval, pois isso pode permitir a extração acidental de código por meio de valores em ${Y}. Veja minha adição na resposta do usuário "anon".
try-catch-finalmente
Esta é a única resposta de trabalho. Irônico que é seu!
Ctrl S
8

Para meus colegas usuários do zsh, a maneira de realizar a mesma coisa que a resposta aceita é usar:

${(P)a}

É chamado de substituição do nome do parâmetro

Isso força o valor do nome do parâmetro a ser interpretado como um nome de parâmetro adicional, cujo valor será usado quando apropriado. Observe que os sinalizadores configurados com um dos tipos de família de comandos (em particular transformações de caso) não são aplicados ao valor do nome usado dessa maneira.

Se usado com um parâmetro aninhado ou substituição de comando, o resultado será considerado como um nome de parâmetro da mesma maneira. Por exemplo, se você tiver 'foo = bar' e 'bar = baz', as cadeias $ {(P) foo}, $ {(P) $ {foo}} e $ {(P) $ (barra de eco) } será expandido para 'baz'.

Da mesma forma, se a própria referência estiver aninhada, a expressão com o sinalizador será tratada como se fosse diretamente substituída pelo nome do parâmetro. É um erro se essa substituição aninhada produzir uma matriz com mais de uma palavra. Por exemplo, se 'name = assoc' em que o parâmetro assoc for uma matriz associativa, '$ {$ {(P) name} [elt]}' se refere ao elemento do subscrito associativo 'elt'.

smac89
fonte
0

shells modernos já suportam matrizes (e até matrizes associativas). Então, por favor, use-os e use menos de avaliação.

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

quando você quiser chamá-lo, echo $ {array [0]}

ghostdog74
fonte
isso funcionaria se eu obter a seqüência de caracteres do argumento de linha de comando (por exemplo, como $1)?
Jena
0

Com base na resposta: 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")
VFein
fonte
0

Teve o mesmo problema com matrizes, eis como fazê-lo se você também estiver manipulando matrizes:

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

Isso produzirá:

ARRAY=ARRAY_NAME[@]
ARRAY=Val0 Val1 Val2
ARRAY[0]=Val0
ARRAY[1]=Val1
ARRAY[2]=Val2
Alexandre Hamon
fonte