如果变量名称存储为字符串,如何获取变量值?


142

如果变量名称为字符串,如何检索bash变量值?

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

内容:

我有一些AMI(Amazon机器映像),我想启动每个AMI的一些实例。他们完成启动后,我要根据其AMI类型设置每个实例。我不想在任何AMI中烘焙大量脚本或秘密密钥,因此我准备了一个通用的启动脚本,并通过可公开访问的链接将其放在S3上。在rc.local中,我放了一小段代码来获取启动脚本并执行它。这就是我在AMI中所拥有的。然后,每个AMI访问一个适用于所有AMI的通用配置脚本和每个配置的特殊设置脚本。这些脚本是私有的,需要签名的URL才能访问它们。

因此,现在,当我启动AMI的实例(my_private_ami_1)时,我为S3上传递的另一个文件传递了一个签名URL,该文件包含键/值对形式的所有私有脚本的签名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类型如何,并且实例可以照顾自己。

Answers:


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 bash中对我有效,但对debian不适用?在debian上,我得到了Bad substitution错误。
2013年

11
@ 23inhouse您是否正在使用运行脚本/bin/sh?如果是这样,请尝试/bin/bash改用。从Debian Squeeze开始,/bin/sh已改为而不是的符号链接dashbashdash不支持此特定语法,将输出Bad substitution错误。
菲尔·罗斯

8
有没有办法使属于数组的变量名起作用?
Loupax 2014年

使用bash在ubuntu上工作
Sergey P. aka azure 2014年

1
@DoronShai这是间接参数扩展的示例,已在Bash参考手册中的gnu.org/software/bash/manual/html_node/…中记载
Phil Ross

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

将Z设置为“ foo”

请小心使用,eval因为这可能会导致通过中的值意外执行代码${Y}。这可能会因代码注入而造成伤害。

例如

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

将创造/tmp/eval-is-evilrm -rf /当然也可以是一些。


ty,救了我的尾巴
拉菲安

9

修改了我的搜索关键字并得到它:)。

eval a=\$$a
谢谢你的时间。


请谨慎使用eval,因为这可能会通过中的值意外执行代码${Y}。请参阅用户“匿名”答案中的补充内容。
最终

这是唯一可行的答案。具有讽刺意味的是,这是你自己的!
Ctrl S

8

对于我的zsh同仁用户,完成与接受的答案相同的事情的方法是使用:

${(P)a}

称为参数名称替换

这将强制将参数名称的值解释为另一个参数名称,将在适当的地方使用其值。请注意,使用排版类型的命令系列之一设置的标志(在特殊情况下是转换)不会应用于以这种方式使用的名称值。

如果与嵌套参数或命令替换一起使用,则其结果将以相同的方式用作参数名称。例如,如果您具有'foo = bar'和'bar = baz',则字符串$ {(P)foo},$ {(P)$ {foo}}和$ {(P)$(echo bar) }将扩展为'baz'。

同样,如果引用本身是嵌套的,则将带有标志的表达式视为直接用参数名称替换。如果此嵌套替换产生一个包含多个单词的数组,则会出现错误。例如,如果参数ass是关联数组的'name = assoc',则'$ {$ {(P)name} [elt]}'是指关联下标'elt'的元素。


0

现代的外壳已经支持数组(甚至是关联数组)。因此,请使用它们,并减少评估时间。

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

然后在您要调用它时,回显$ {array [0]}


如果我从命令行参数中获取字符串(例如$1),此方法会起作用吗?
耶拿

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
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.