Você pode fazer isso, mas requer pelo menos duas avaliações de variáveis de shell e, normalmente, tudo o que você consegue é um. Isso é por design - quero dizer, o shell é onde estão todas as suas coisas, então é melhor limitar o mínimo ao inesperado e evitar abrir as portas atrás das portas se você puder evitar. Em qualquer caso, você definitivamente tem à sua disposição o eval
shell embutido:
% one=two ; two=three ; eval echo \$$one
> three
% eval "one=\$$two" ; echo $one
> three
Não armazena one
- > two
pointer, mas ele avalia seus argumentos como uma única instrução de shell. Se isso é um pouco claro para você, você não está sozinho. Isso basicamente significa que o shell executa a mesma linha duas vezes, ou pelo menos o mais próximo possível, e todas as atribuições do segundo passe são afetadas pelas expansões do primeiro passo - o que normalmente não é o caso, como você demonstra em sua pergunta. Isso também significa que o valor literal de two
de um determinado ponto no tempo é armazenado em one
- copiado, não vinculado, portanto:
% one=two ; two=three
% eval echo \$$one ; two=four ; eval echo \$$one
> three
> three
% echo $two
> four
Mas o que há com a barra invertida? Bem, é aqui que fica confuso - porque você está fazendo duas passagens você tem que citar suas citações. A primeira passagem expande $one
para two
e retira o primeiro nível de cotações, portanto, bye-bye \ backslash, mas o sinal de dólar entre aspas permanece e assim $two
se torna three
na segunda passagem. Isso fica muito louco muito rápido .
As citações da Shell são difíceis o suficiente para lidar da forma como estão - apenas tente citar uma citação simples. Camada-los e você está pedindo problemas, tira, avaliar, tira, avaliar e você está indo nada seguro - porque as citações estão lá para proteger os valores de parâmetros de shell e variáveis de ambiente e shell de seus valores.
Então, o que você fez é armazenar um literal $
cifrão dentro do valor de sua variável. Você não armazenou um caminho para $HOME
porque o shell não expandiu seu valor durante a atribuição - novamente, por design .
% dir=some_dir ; eval "$dir=\$HOME" ; echo $some_dir
> /your/$HOME/path/
Você não precisa perguntar muito sobre essas coisas antes de ouvir o mal eval
. É comumente chamado assim e por boas razões. Olhe:
two=var\ \;rm\ -f\ /all/your/stuff ; eval home=$two
Acima de casa é atribuída a expansão de $ dois. A porção home=
da declaração é avaliada duas vezes - após a primeira passagem e antes de a segunda, home brevemente é igual a "$ two"; mas no segundo, depois que as aspas são retiradas, $home
expande para var
e /all/your/stuff
é igual a 0. Esse também é um exemplo de citação super básico, pode dar errado situação complicada - e apenas a exigência de eval
tende a ser complicada.
Existem outras maneiras de fazer isso - o GNOUC observa a designação de inversão ${!
bash específica }
(acho que é assim que é chamada ...) que provavelmente faz a mesma coisa, mas de uma forma que bash
tentou salvaguardar. Isso é uma coisa boa. Você também pode - e provavelmente é uma boa ideia - escrever uma função para cunhar os valores que deseja quando é chamada:
_home() { exec 2>/dev/null ; set -- /home/*/ ; for h do (
cd "$h" && cd "$dir" && printf %s\n "$dir" )
done
} ; var="$(_home)" ; echo "$var"
> probably...
> the...
> result...
> you...
> wanted...
Quase tão perigoso quanto eval
pode ser um pouco de imaginação em combinação com o uso do .
do shell também. Como o trabalho de .
é executar comandos no ambiente de shell atual em vez de subclassificar como os pipes e etc, é possível construir uma instrução avaliada duas vezes que pode afetar suas variáveis de ambiente com pouco confusão.
Por exemplo, se você não citar o limitador em um here-document
, seu conteúdo estará sujeito à expansão do shell. Se você levar isso mais adiante e .
source, você pode executar os resultados de suas expansões. Assim:
% . <<HERE /dev/stdin
> ${one=two}three=four
> home='$HOME'
> HERE
% [ "$home" = "$HOME" ] && echo $twothree
> four
Veja, desta forma, pelo menos, as aspas são mais fáceis porque elas não são removidas, exceto de dentro de uma expansão, mas elas ainda podem ser complicadas quando suas expansões contêm citações. De qualquer forma, isso envolve o que eu sei sobre o assunto.
Na verdade, mais uma coisa, e isso é super arriscado, mas é o seu computador:
% var=eval\ echo\ \$HOME
% $var
> /YOUR/HOME
Mas ...
% cd eval echo $HOME
obviamente não funciona ...