考虑以下代码:
#!/bin/bash -x
VAR='1 2 3'
bash -c "echo "\$$VAR""
eval "echo "\$$VAR""
bash -c "echo \"\$$VAR\""
eval "echo \"\$$VAR\""
哪些输出:
+ VAR='1 2 3'
+ bash -c 'echo $1' 2 3
3
+ eval 'echo $1' 2 3
++ echo 2 3
2 3
+ bash -c 'echo "$1 2 3"'
2 3
+ eval 'echo "$1 2 3"'
++ echo ' 2 3'
2 3
似乎都是eval
和 bash -c
以相同的方式解释代码,即 "echo "\$$VAR""
至 'echo $1' 2 3
和 "echo \"\$$VAR\""
至 'echo "$1 2 3"'
.
我似乎注意到的唯一区别是 bash -c
打开一个子 shell ,从而改变 eval
的结果.例如,在
bash -c 'echo $1' 2 3
2 和 3 是子 shell 的位置参数。另一方面,在
eval 'echo $1' 2 3
它们只是 echo
的另一个参数.
所以我的问题是,-c
选项( bash -c
, sh -c
或其他 shell 的等价物)可以安全使用还是像 eval
一样邪恶?
最佳答案
是的,您应该避免在 shell 脚本中使用 sh -c
和等效项,就像您避免使用 eval
一样。
eval "$foo"
...归根结底,这是一种安全风险,因为它将数据视为代码,从一开始就重新启动解析过程(因此,运行扩展、重定向等)。此外,由于在此过程中考虑了引用上下文,因此正在评估的数据中的内容能够转义引号、终止命令,并以其他方式试图逃避任何安全措施。
sh -c "$foo"
做同样的事情——运行扩展、重定向等——只在一个全新的 shell 中(不共享非导出变量或其他状态)。
这两者都意味着像 $(rm -rf/)
这样的内容很容易被扩展,除非非常小心,而不是确保——通常情况下——< em>数据只会被视为数据,这是编写安全代码的基本要素。
现在,令人高兴的是,当您使用 bash
(或 zsh 或 ksh93)而不是 sh
时,您可以 在几乎所有情况下都避免使用 eval
。
例如:
value=$(eval "echo \$$varname")
...可以替换为:
value=${!varname}
...在 bash 中,
eval "$varname="'$value'
...可以替换为...
printf -v varname %s "$value"
...等等(ksh93 和 zsh 具有与后者的直接等价物);涉及关联映射等的更高级公式最好通过新的 bash 4.3(和 ksh93)namevar 支持来解决。
值得注意的是,bash -c
不会在上述大多数示例中有效地替换 eval
,因为它不在相同的上下文:当子进程退出时,对 shell 状态所做的更改将被丢弃;因此,bash -c
不仅买不到安全性,而且作为 eval
的替代品也不能工作。
关于bash - 我应该避免在我的 shell 脚本中使用 bash -c、sh -c 和其他 shell 的等效项吗?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/31267791/