我想使用 动态地为变量赋值eval
。以下虚拟示例有效:
var_name="fruit"
var_value="orange"
eval $(echo $var_name=$var_value)
echo $fruit
orange
但是,当变量值包含空格时,即使放在双引号之间eval
也会返回错误:$var_value
var_name="fruit"
var_value="blue orange"
eval $(echo $var_name="$var_value")
bash: orange : command not found
有什么办法可以绕过这个吗?
答案1
不要使用 eval,使用declare
$ declare "$var_name=$var_value"
$ echo "fruit: >$fruit<"
fruit: >blue orange<
答案2
不要用于eval
此目的;使用declare
。
var_name="fruit"
var_value="blue orange"
declare "$var_name=$var_value"
请注意,单词拆分不是问题,因为 之后的所有内容=
都被视为 的值declare
,而不仅仅是第一个单词。
在bash
4.3 中,命名引用使这变得更简单一些。
$ declare -n var_name=fruit
$ var_name="blue orange"
$ echo $fruit
blue orange
你能让eval
工作,但你仍然不应该:)使用eval
是一个坏习惯。
$ eval "$(printf "%q=%q" "$var_name" "$var_value")"
答案3
一个好的使用方法eval
是将其替换echo
为测试。echo
并且eval
工作原理相同(如果我们抛开某些实现(例如在某些条件下)\x
所做的扩展)。echo
bash
两个命令都用一个空格来连接它们的参数。不同之处在于echo
显示结果同时eval
评估/解释作为 shell 代码的结果。
那么,看看有什么shell代码
eval $(echo $var_name=$var_value)
会评估,你可以运行:
$ echo $(echo $var_name=$var_value)
fruit=blue orange
这不是你想要的,你想要的是:
fruit=$var_value
另外,$(echo ...)
在这里使用没有意义。
要输出以上内容,您需要运行:
$ echo "$var_name=\$var_value"
fruit=$var_value
因此,简单地解释一下:
eval "$var_name=\$var_value"
请注意,它也可用于设置单个数组元素:
var_name='myarray[23]'
var_value='something'
eval "$var_name=\$var_value"
正如其他人所说,如果您不关心代码是否bash
具体,您可以使用declare
:
declare "$var_name=$var_value"
但请注意,它有一些副作用。
它将变量的范围限制为运行它的函数。因此您不能在以下情况中使用它:
setvar() {
var_name=$1 var_value=$2
declare "$var_name=$var_value"
}
setvar foo bar
因为这会声明一个foo
局部变量,setvar
所以是没有用的。
bash-4.2
添加了一个-g
选项来declare
声明全球的变量,但这也不是我们想要的,因为我们setvar
会设置一个全球的如果调用者是一个函数,则 var 与调用者的 var 相反,如下所示:
setvar() {
var_name=$1 var_value=$2
declare -g "$var_name=$var_value"
}
foo() {
local myvar
setvar myvar 'some value'
echo "1: $myvar"
}
foo
echo "2: $myvar"
这将输出:
1:
2: some value
另外,请注意, whiledeclare
被调用declare
(实际上bash
借用了 Korn shell 内置函数的概念typeset
),如果变量已经设置,declare
则不会声明新变量,并且完成赋值的方式取决于变量的类型。
例如:
varname=foo
varvalue='([PATH=1000]=something)'
declare "$varname=$varvalue"
如果varname
之前声明为标量,大批或者关联数组。
还要注意,如果 的内容没有得到严格控制,declare
并不比 更安全。eval
$varname
例如,如果包含的话eval "$varname=\$varvalue"
, 和declare "$varname=$varvalue"
都会重新启动系统。$varname
a[$(reboot)1]
答案4
使用死引用即。撇号。
eval $(echo $var_name='$var_value')
它对我有用。