是否可以使用Shell脚本打印变量内容的内容?(间接引用)


13

假设我已经声明了以下变量:

$ var='$test'
$ test="my string"

如果打印其内容,则会看到以下内容:

$ echo $var
$test

$ echo $test
my string

我想找到一种方法来打印的内容$var(即的内容$test)。因此,我尝试执行以下操作:

$ echo $(echo $var)
$test

但是这里的结果是$test,不是"my string"。。。是否可以使用bash打印变量内容的内容?


您能否编辑您的文章以说明您使用的是哪个Shell,或者您有什么可移植性要求?
Michael Homer

@MichaelHomer当然可以,但是我如何才能检查此信息呢?
Rafael Muynarsk '18

您选择的东西多于要检查的东西。例如,你有运行脚本ash,或者bash,或者csh,或者dash,...,或者zsh,或者POSIX sh,或者你需要在不同系统之间的工作?
Michael Homer

@MichaelHomer啊,我知道了...我正在使用bash。我将更改最后一个问题,然后插入一个新标签。
Rafael Muynarsk

Answers:


21

您可以使用bash的间接变量扩展来完成此操作(只要可以$从参考变量中删除,就可以了):

$ var=test
$ test="my string"
$ echo "$var"
test
$ echo "${!var}"
my string

3.5.3 Shell参数扩展


10

对于其中包含的变量名称var带有前缀的情况,$可以使用eval

$ var='$test'
$ test="my string"
$ eval echo $var
my string

这里会发生什么:

  • bash扩展$var为value $test,产生一个eval echo $test命令;
  • eval计算echo $test表达式并产生期望的结果。

请注意,eval通常使用可能会很危险(取决于中存储的内容var),因此最好避免使用它。间接扩展功能更适合您的情况(但您需要摆脱$登录$test)。


当然,那是一个错误的类型。原始帖子带有单引号。固定。
Danila Kiver

4
我总是建议使用双引号引用变量(以避免意外的单词拆分和通配符扩展引起麻烦)。有了eval,你需要双引号的两层,该行:eval echo "\"$var\""。提醒您,这与eval您提到的其他使用危险无关。
Gordon Davisson

9

Jesse_b的答案类似,但使用名称引用变量而不是变量间接寻址(需要bash4.3+):

$ declare -n var=test
$ test="my string"
$ echo "$var"
my string

名称引用变量var保存其引用的变量的名称。将变量取消引用为时$var,将返回另一个变量的值。

bash 递归解析名称引用:

$ declare -n var1=var2
$ declare -n var2=test
$ test="hello world"
$ echo "$var1"
hello world

为了完整bash起见,根据需要,使用关联数组(4.0及更高版本)也是解决此问题的一种方法:

$ declare -A strings
$ strings[test]="my string"
$ var=test
$ echo "${strings[$var]}"
my string

这提供了一种更灵活的方式,可以通过可能动态确定的键或名称访问多个值。如果您想在一个数组中收集特定类别的所有值,但是仍然能够通过某些键(例如,可通过ID访问的名称或可通过目的访问的路径名)访问它们,则可能会更可取,因为它不会污染脚本的变量名称空间。


3

zsh

$ var='$test'
$ test='*'
$ printf '%s\n' ${(e)var}
*

带有任何类似伯恩的贝壳

$ eval 'printf "%s\n" "'"$var"'"'
*

请记住,在这些shell中,必须使用引号将变量扩展名括起来,以防止split + glob(zsh是一个例外),echo并且不能将其用于任意数据。

由于既(e)eval有shell代码的评估,这是很重要的内容$var留在你的控制范围内另有可以是任意命令注入漏洞(用相同${!var}的方法)。

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.