在阅读了Bash 手册页和这篇文章之后,我仍然无法理解该eval命令的确切作用以及它的典型用途。
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
这里到底发生了什么,美元符号和反斜杠如何与问题联系起来?
eval接受一个字符串作为它的参数,并评估它,就好像你在命令行上输入了那个字符串一样。(如果你传递了几个参数,它们首先用它们之间的空格连接起来。)
${$n}是 bash 中的语法错误。在大括号内,你只能有一个变量名,带有一些可能的前缀和后缀,但你不能有任意的 bash 语法,特别是你不能使用变量扩展。有一种说法是“名称在此变量中的变量的值”,但是:
${$n}
echo ${!n} one
$(...)在子shell 中运行括号内指定的命令(即在从当前shell 继承所有设置(例如变量值)的单独进程中),并收集其输出。所以作为 shell 命令echo $($n)运行,并显示其输出。$n由于$n计算结果为1,因此$($n)尝试运行1不存在的命令。
$(...)
echo $($n)
$n
1
$($n)
eval echo \${$n}运行传递给的参数eval。展开后参数为echo和${1}。所以eval echo \${$n}运行命令echo ${1}。
eval echo \${$n}
echo
${1}
echo ${1}
请注意,大多数情况下,您必须在变量替换和命令替换周围使用双引号(即,只要有 a $)"$foo", "$(foo)":。 总是在变量和命令替换周围加上双引号 ,除非你知道你需要把它们去掉。如果没有双引号,shell 会执行字段拆分(即,它将变量的值或命令的输出拆分为单独的单词),然后将每个单词视为通配符模式。例如:
$
"$foo", "$(foo)"
$ 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当您需要构建包含运算符、保留字等的较长命令时,它仍然很有用。
${!VAR}