bash - 我应该避免在我的 shell 脚本中使用 bash -c、sh -c 和其他 shell 的等效项吗?

标签 bash shell sh

考虑以下代码:

#!/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

似乎都是evalbash -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 -csh -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/

相关文章:

python - 如何从 Python 脚本在终端中执行命令?

linux - 跟踪后台进程的 PID 并将其与进程名称一起存储在 linux 中

shell - 如何使 sed 脚本替换文件中的内容?

javascript - 在 React 中 - 如何从 .sh(Shell 脚本)文件中获取值?

shell - Bourne Shell For i in (seq)

linux - 更改 bash 文件备份的后缀

linux - (已回答) Bash SH 中的 find 命令未按预期工作

bash - .sh 脚本的第二行不执行

git - SSH-ksh : git: not found

linux - 在 bash 脚本中使用条件检查字符串参数