在Bash中的eval命令及其典型用途?

内容来源于 Stack Overflow,并遵循CC BY-SA 3.0许可协议进行翻译与使用

  • 回答 (2)
  • 关注 (0)
  • 查看 (28)

我仍然无法理解eval命令的具体用途以及哪些是典型用途。例如,如果我们这样做:

bash$ set -- one two three  # sets $1 $2 $3
bash$ echo $1
one
bash$ n=1
bash$ echo ${$n}       ## First attempt to echo $1 using brackets fails
bash: ${$n}: bad substitution
bash$ echo $($n)       ## Second attempt to echo $1 using parentheses fails
bash: 1: command not found
bash$ eval echo \${$n} ## Third attempt to echo $1 using 'eval' succeeds
one

到底发生了什么?美元符号和反斜杠如何与问题联系在一起?

提问于
用户回答回答于

eval接受一个字符串作为它的参数,并对它进行评估,就好像你在命令行上键入了该字符串一样。(如果你传递了几个参数,它们首先与它们之间的空格相连接。)

${$n}是bash中的语法错误。在花括号里面,你只能有一个变量名,带有一些可能的前缀和后缀,但是你不能有任意的bash语法,特别是你不能使用变量扩展。虽然有一种说法是“变量名称在这个变量中的值”,但是:

echo ${!n}
one

$(…)运行子shell中圆括号内指定的命令(即在继承所有设置(如当前shell的变量值)的单独进程中),并收集其输出。因此作为shell命令echo $($n)运行$n,并显示其输出。自$n评估以来1$($n)尝试运行1不存在的命令。

eval echo \${$n}运行传递给的参数eval。扩展后,参数是echo${1}。所以eval echo \${$n}运行命令echo ${1}

请注意,大多数情况下,你必须在变量替换和命令暂停(即任何时候有$)之间使用双引号:"$foo", "$(foo)"。除非你知道你需要关闭它们,否则总是在变量和命令替换周围放置双引号。如果没有双引号,shell会执行字段拆分(即它将变量的值或命令的输出拆分为单独的单词),然后将每个单词视为通配符模式。例如:

$ ls
file1 file2 otherfile
$ set -- 'f* *'
$ echo "$1"
f* *
$ echo $1
file1 file2 file1 file2 otherfile
$ n=1
$ eval echo \${$n}
file1 file2 file1 file2 otherfile
$eval echo \"\${$n}\"
f* *
$ echo "${!n}"
f* *

eval不常使用。在某些shell中,最常见的用途是获取名称在运行时才知道的变量的值。在bash中,这是没有必要的,这要归功于${!VAR}语法。eval当您需要构建包含运算符,保留字等的较长命令时仍然有用。

用户回答回答于

简单地将eval视为“在执行前额外一次评估你的表达”

eval echo \${$n}成为echo $1第一轮评估之后。要注意的三点变化:

  • \$成为$(需要反斜杠,否则它会尝试来评估${$n}的,这意味着一个命名的变量{$n},这是不允许的)
  • $n 被评估为 1
  • eval消失

在第二轮中,基本上echo $1可以直接执行。

所以eval <some command>首先会评估<some command>(通过在这里评估我的意思是替代变量,用正确的替换转义字符等),然后再次运行结果表达式。

eval当你想要动态地创建变量或者读取专门设计为读取的程序的输出时使用。例子见http://mywiki.wooledge.org/BashFAQ/048。该链接还包含一些典型的使用方式eval以及与之相关的风险。

扫码关注云+社区