与仅评估变量相比,eval/bash -c的意义何在?

Jam*_* Ko 8 unix linux bash shell sh

假设您将以下命令存储在变量中:

COMMAND='echo hello'
Run Code Online (Sandbox Code Playgroud)

有什么区别

$ eval "$COMMAND"
hello

$ bash -c "$COMMAND"
hello

$ $COMMAND
hello
Run Code Online (Sandbox Code Playgroud)

?为什么最后一个版本几乎从不使用,如果它更短并且(据我所知)完全相同的事情?

Cha*_*ffy 11

第三种形式与其他两种形式完全不同 - 但要理解为什么,我们需要在解释命令时按bash进行操作,并查看每种方法在使用时遵循哪些操作.

Bash解析阶段

  1. 报价处理
  2. 拆分命令
  3. 特殊操作员解析
  4. 展开
  5. 单词分裂
  6. 通配符
  7. 执行

运用 eval "$string"

eval "$string"遵循从#1开始的所有上述步骤.从而:

  • 字符串中的字面引号成为语法引号
  • 特殊操作员如>()被处理
  • 像这样的扩展$foo很荣幸
  • 这些扩展的结果在字符上分成空格分成单独的单词
  • 如果这些单词解析为相同且具有可用匹配,那么这些单词将扩展为globs,最后执行该命令.

运用 sh -c "$string"

...执行与此相同eval,但在作为单独进程启动的新shell中 ; 因此,当这个新进程退出时,对变量状态,当前目录等的更改将到期.(注意,那就是,新的外壳可以是不同的解释支持不同的语言;即sh -c "foo"不支持相同的语法bash,ksh,zsh等做的).


运用 $string

...从第5步开始,"Word Splitting".

这是什么意思?

行情不受尊重.

printf '%s\n' "two words"因此printf %s\n "two words",将解析为(通常/期望的行为)printf %s\n two words(由shell使用引号).

不会分裂成多个命令(;s,&s或类似).

从而:

s='echo foo && echo bar'
$s
Run Code Online (Sandbox Code Playgroud)

...将发出以下输出:

foo && echo bar
Run Code Online (Sandbox Code Playgroud)

...而不是以下,否则将是预期的:

foo
bar
Run Code Online (Sandbox Code Playgroud)

特殊运营商和扩张不受尊重.

$(foo),不$foo,不<(foo),等等

重定向不受尊重.

>foo或者2>&1只是字符串拆分创建的另一个单词,而不是shell指令.