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

时间:2009-12-17 11:59:33

标签: string bash

如果我将变量名称作为字符串,如何检索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和每个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类型和实例可以自己处理。

8 个答案:

答案 0 :(得分:190)

您可以使用${!a}

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

这是间接parameter expansion

的示例
  

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

     

如果parameter的第一个字符是感叹号(!),那么   引入了一个变量间接层。 Bash使用的值   变量由parameter的其余部分组成,作为   变量;然后展开此变量,并在该变量中使用该值   替换的其余部分,而不是parameter本身的值。

答案 1 :(得分:24)

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

将Z设为“foo”

使用eval

小心,因为这可能允许通过${Y}中的值实际执行代码。这可能会通过代码注入造成伤害。

例如

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

会创建/tmp/eval-is-evil。当然,这也可能是一些rm -rf /

答案 2 :(得分:8)

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

eval a=\$$a
感谢您的时间。

答案 3 :(得分:4)

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

${(P)a}

它被称为Parameter name replacement

  

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

     

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

     

同样,如果引用本身是嵌套的,则表达式为   flag被视为直接替换为参数名称。   如果此嵌套替换产生的数组更多,则会出错   不止一个字。例如,如果'name = assoc',则参数assoc   是一个关联数组,然后'$ {$ {(P)name} [elt]}'指的是   关联下标'elt'的元素。

答案 4 :(得分:1)

数组也有同样的问题,如果您也要操纵数组,这是怎么做:

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

答案 5 :(得分:1)

在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

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

答案 6 :(得分:0)

现代shell已经支持数组(甚至是关联数组)。所以请使用它们,少用eval。

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

然后当你想调用它时,回显$ {array [0]}

答案 7 :(得分:0)

根据答案:https://unix.stackexchange.com/a/111627

    def solution(prices: Array[Int]): Int = {
      prices.foldLeft((prices.headOption.getOrElse(0), 0: Int)) { (tuple, price) =>
        (Math.min(tuple._1, price), Math.max(tuple._2, price - tuple._1))
      }._2
    }