eval 通过两次 shell 解析实现动态变量引用与命令执行,但存在严重注入风险;应优先使用间接引用 ${!ref}、关联数组或名称引用等更安全的替代方案。

直接用 eval 拼接并执行含变量的动态语句,本质是让 shell 对字符串做**两次解析**:第一次展开普通变量,第二次把结果当命令再执行。它能实现间接引用、动态赋值、运行拼出来的命令等,但必须严格控制输入来源——不可信数据进 eval 就等于交出执行权。
基础拼接:用 $${var} 获取拼出的变量值
比如已有 a="aaa" 和 aaabbb="1",想通过 ${a}bbb 得到变量名 aaabbb 并取其值:
-
eval echo \$${a}bbb→ 先展开${a}成aaa,得到$aaabbb,再解析为1输出 - 若要存入新变量:
result=$(eval echo \$${a}bbb),result就是"1" - 注意
\$的写法:反斜杠阻止第一次展开,确保$aaabbb留到第二次解析
动态赋值:把值写进拼出来的变量名
想把字符串 "hello" 赋给名为 user_data_123 的变量,其中 123 来自变量 id:
-
id=123; eval "user_data_${id}=hello"→ 第一次展开成user_data_123=hello,第二次执行赋值 - 赋值后可用
echo $user_data_123验证 - 如果值含空格或特殊字符,务必用双引号包裹整个赋值式,避免被 shell 拆分
执行拼出的完整命令
当命令结构依赖运行时变量(如文件名、参数开关),可先拼字符串再 eval:
-
cmd="ls -l"; dir="/tmp"; eval "$cmd $dir"→ 展开为ls -l /tmp并执行 - 管道、重定向也能拼:
pipe="|"; eval "ps aux $pipe grep nginx" - 关键点:所有参与拼接的变量必须已知、可控;不能把用户输入、环境变量、网络响应直接塞进去
比 eval 更安全的替代方式
多数场景其实不需要 eval,改用这些方法更清晰、无注入风险:
-
间接引用:
var1="hello"; ref="var1"; echo ${!ref}→ 直接输出hello,无需eval -
命令替换:
files=$(ls *.log),而不是eval "files=\$(ls *.log)" -
关联数组(Bash 4.0+):
declare -A data; key="user_123"; data[$key]="active"; echo ${data[$key]} -
名称引用(Bash 4.3+):
declare -n alias_ref=real_var; real_var="ok"; echo $alias_ref











