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

How to get a variable value if variable name is stored as string?

提问人:bhups 提问时间:12/17/2009 最后编辑:Communitybhups 更新时间:9/22/2023 访问量:167990

问:

如果我的变量名称为字符串,如何检索 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 的通用配置脚本,并为每个 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"
...
当启动脚本运行时,它会下载上面的文件并完成。然后,它会检查其 AMI 类型,并为自己选择正确的设置脚本。source

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 类型如何,并且实例可以自行处理。

字符串 bash

评论


答:

13赞 bhups 12/17/2009 #1

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

eval a=\$$a
感谢您抽出时间接受采访。

评论

0赞 try-catch-finally 5/11/2017
使用 eval 时要小心,因为这可能会允许通过 中的值意外地执行代码。请参阅我在用户“anon”的答案中的补充。${Y}
0赞 Ctrl S 6/25/2018
这是唯一可行的答案。具有讽刺意味的是,这是你自己的!
402赞 Phil Ross 12/17/2009 #2

您可以使用:${!a}

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

这是间接参数扩展的示例:

参数扩展的基本形式是 。替换的值。${parameter}parameter

如果第一个字符是感叹号 (!),则它 引入了可变间接级别。Bash 使用 由其余部分组成的变量作为 变量;然后展开此变量,并在 其余的替代,而不是它本身的价值。parameterparameterparameter

评论

4赞 23inhouse 8/8/2013
这在 OSX bash 中对我有用,但对 debian 不起作用?在 debian 上我遇到错误。Bad substitution
16赞 Phil Ross 8/8/2013
@23inhouse 您是否使用 ?如果是这样,请尝试改用。从 Debian Squeeze 开始,它被更改为 dash 而不是 bash 的符号链接。 不支持此特定语法,将输出错误。/bin/sh/bin/bash/bin/shdashBad substitution
10赞 Loupax 1/15/2014
有没有办法使这适用于属于数组的变量名称?
0赞 Sergey P. aka azure 9/25/2014
使用 bash 在 ubuntu 上工作
1赞 Phil Ross 5/28/2015
@DoronShai 这是间接参数扩展的一个示例,记录在 Bash 参考手册中,gnu.org/software/bash/manual/html_node/...
42赞 anon 12/17/2009 #3
X=foo
Y=X
eval "Z=\$$Y"

设置为 。Zfoo

评论

0赞 Jens 10/15/2023
在 Linux-Bash 下:结果显示:zuzu_1number=1 eval "Z=zuzu_\$number" echo "$Z"
1赞 ghostdog74 12/17/2009 #4

现代 shell 已经支持数组(甚至关联数组)。因此,请务必使用它们,并减少使用eval。

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

那么当你想调用它时,echo ${array[0]}

评论

0赞 jena 11/15/2018
如果我从命令行参数(例如 as )获取字符串,这会起作用吗?$1
25赞 smac89 12/16/2017 #5

对于我的 zsh 用户来说,完成与公认的答案相同的事情的方法是使用:

echo ${(P)a} # outputs 'this is the real value'

它被恰当地称为参数名称替换。也适用于存储在数组中的变量。

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

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

同样,如果引用本身是嵌套的,则带有 标志被视为直接替换为参数名称。 如果此嵌套替换生成一个具有 more 的数组,则这是一个错误 比一个字。例如,如果 'name=assoc' 其中参数 assoc 是一个关联数组,则 '${${(P)name}[elt]}' 指的是 元素的关联下标“elt”。

0赞 VFein 7/18/2019 #6

基于答案: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")
9赞 Alexandre Hamon 4/17/2020 #7

数组也有同样的问题,如果您也在操作数组,以下是该怎么做:

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

评论

1赞 Reorx 2/7/2022
+1 因为这是数组的唯一正确答案,为了更清楚起见,字符串必须有后缀才能获得完整的数组。[@]
2赞 user8150417 10/20/2020 #8

在 bash 4.3 中,引入了对集合变量的 '-v' 测试。同时,添加了“nameref”声明。这两个功能与间接运算符 (!) 一起启用了上一个示例的简化版本:

get_value()
{
  declare -n var_name=$1
  if [[ -v var_name ]]
  then
    echo "${var_name}"
  else
    echo "variable with name <${!var_name}> is not set"
  fi
}

test=123
get_value test
123

test="\$(echo \"something nasty\")"
get_value test
$(echo "something nasty")

unset test
get_value test
variable with name <test> is not set

由于这种方法消除了对“eval”的需要,因此更安全。 此代码在 bash 5.0.3(1) 下检查。

15赞 Mr Z 10/26/2021 #9

在 bash 4.3+ 中,您可以使用:declare -n

#!/usr/bin/env bash

var="this is the real value"
var_name="var"

declare -n var_ref=$var_name
echo "${var_ref}"
-1赞 MingalevME 8/18/2022 #10
VALUE=$(eval "echo \$$SOME_VAR_NAME")

SSH_KEY_FILE_PATH_FOO="/tmp/key"
SSH_KEY_FILE_PATH_VAR_NAME_PREFIX="SSH_KEY_FILE_PATH"
SSH_KEY_FILE_PATH_VAR_NAME_SUFFIX="FOO"
SSH_KEY_FILE_PATH=$(eval "echo \$${SSH_KEY_FILE_PATH_VAR_NAME_PREFIX}_${SSH_KEY_FILE_PATH_VAR_NAME_SUFFIX}")
echo "$SSH_KEY_FILE_PATH"
/tmp/key
1赞 FedKad 6/7/2023 #11

扩展@MrZ的答案:

使用此方法,可以生成对动态生成名称的任何变量的引用。例如:declare -n

$ var_one='This is variable 1'
$ ind=one
$ declare -n var_ref=var_$ind
$ echo $var_ref
This is variable 1
$ ind=two
$ echo $var_ref
This is variable 1
$ declare -n var_ref=var_$ind
$ echo $var_ref

$ var_two="And this is the second variable"
$ echo $var_ref
And this is the second variable