如何使用 eval 将包含空格的值分配给 bash 中的变量

如何使用 eval 将包含空格的值分配给 bash 中的变量

我想使用 动态地为变量赋值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,而不仅仅是第一个单词。

bash4.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所做的扩展)。echobash

两个命令都用一个空格来连接它们的参数。不同之处在于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"都会重新启动系统。$varnamea[$(reboot)1]

答案4

使用死引用即。撇号。
eval $(echo $var_name='$var_value')
它对我有用。

相关内容