小编典典

Bash 中的“eval”命令及其典型用途

all

在阅读了Bash
手册页
这篇文章之后,我仍然无法理解该eval命令的确切作用以及它的典型用途。

例如,如果我们这样做:

$ set -- one two three  # Sets $1 $2 $3
$ echo $1
one

$ n=1
$ echo ${$n}       ## First attempt to echo $1 using brackets fails
bash: ${$n}: bad substitution

$ echo $($n)       ## Second attempt to echo $1 using parentheses fails
bash: 1: command not found

$ eval echo \${$n} ## Third attempt to echo $1 using 'eval' succeeds
one

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


阅读 118

收藏
2022-07-27

共1个答案

小编典典

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}

请注意,大多数情况下,您必须在变量替换和命令替换周围使用双引号(即,只要有 a $"$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 中,最常见的用途是获取名称直到运行时才知道的变量的值。${!VAR}在 bash
中,由于语法原因,这不是必需的。eval当您需要构建包含运算符、保留字等的较长命令时,它仍然很有用。

2022-07-27