eval在Linux中将参数拼接成字符串并由当前shell重新解析执行,能修改当前环境,但存在安全风险;应优先用命令数组替代,必要时需严格校验输入并调试输出。

eval 在 Linux 函数中用于动态拼接并执行命令字符串,但它不是“调用子命令”的常规方式,而是把字符串当作 shell 代码来解析执行。关键在于:它不安全、易出错,但某些场景下(如构建动态命令、兼容旧脚本)仍需谨慎使用。
理解 eval 的作用机制
eval 接收一个或多个参数,将它们**先拼接成单个字符串**,再由当前 shell 重新解析执行(经历变量展开、命令替换、重定向解析等完整解析流程)。例如:
name="ls"; opt="-l"; eval "$name $opt /tmp" 等价于直接运行 ls -l /tmp。
注意:它不是 fork 子 shell 执行,而是在当前 shell 环境中解析并运行——所以能修改当前变量、cd 切换目录等。
在函数中安全拼接并执行动态命令
常见需求:根据参数决定调用哪个命令、带哪些选项。推荐做法是先构造命令数组(更安全),仅在必须时用 eval:
- 避免直接拼接用户输入:eval "cmd $user_input" 可能导致命令注入(如 $user_input='; rm -rf /')
- 优先用数组 + "${array[@]}":例如 cmd=(ls -l); "${cmd[@]}" /tmp
- 若必须用 eval,先清理/校验输入:只允许字母、数字、下划线、固定路径;用 case 或正则过滤
- 调试时加 echo 查看实际执行串:echo "Executing: $cmd_str"; eval "$cmd_str"
典型实用示例:动态选择工具并传参
比如写一个 run_tool 函数,根据第一个参数选命令,其余为参数:
run_tool() {
local tool="$1"; shift
case "$tool" in
find|grep|awk) ;;
*) echo "Unsupported tool: $tool" >&2; return 1;;
esac
eval "$tool \"\$@\"" # 安全点:只对已知命令 + 经过引号保护的 "$@" 执行
}
调用:run_tool grep -i "hello" file.txt → 实际执行 grep -i "hello" file.txt。
替代 eval 的更健壮方案
多数情况下,可用以下方式代替 eval,更清晰、更安全:
- 命令别名或函数封装:为每个工具写独立函数,用 dispatch 模式分发
- 间接引用(间接变量):用 declare -n 或 ${!var} 处理变量名,而非命令名
- exec + 数组:构建命令数组后用 exec "${cmd[@]}" 替换当前进程(适合终端工具)
- 使用 env -i 或 setsid 隔离环境,若真需动态执行不可信字符串(仍不推荐)


















