Linux中命令拼接应优先用函数封装或数组执行,避免eval;必须用eval时须严格过滤可信变量并先echo调试。

Linux 中通过变量拼装命令并执行,核心是让 Shell 正确解析变量内容为可运行的命令结构。但直接拼接再执行(比如用 eval)容易引入安全和逻辑风险。关键不在于“能不能拼”,而在于“怎么拼得可控、可读、可维护”。
优先用函数封装代替字符串拼接
大多数动态场景其实不需要把命令变成字符串再执行。用函数封装逻辑更清晰、更安全:
- 把命令逻辑写成函数,参数通过位置变量传入
- 避免变量中混入用户输入、路径名、选项等不可信内容
- 示例:
run_ls() { ls -l "$1" | grep "$2"; }
run_ls "/etc" "passwd"
必须拼接时,用数组存命令再执行
Shell 数组天然支持带空格、特殊字符的参数,比字符串拼接可靠得多:
- 先定义数组:cmd=(ls -l "$target_dir")
- 追加条件参数:[[ "$verbose" == "yes" ]] && cmd+=(-v)
- 最终执行:"${cmd[@]}" —— 注意必须加引号和
@ - 这种方式完全规避了 word splitting 和 glob 展开错误
eval 是最后手段,且必须严格过滤输入
如果确实要动态生成含变量、命令替换或重定向的完整命令行,eval 不可避免,但需满足:
- 所有参与拼接的变量必须来自可信源(如脚本内部常量、配置文件固定值)
- 绝对禁止将用户输入、环境变量(如
$USER、$PWD)、未清理的文件名直接代入eval - 使用单引号包裹静态部分,双引号包裹已清洗的变量:eval 'ls -l' "$safe_path"
- 调试时先用 echo 打印最终命令,确认无意外字符再执行
避免常见陷阱
这些做法看似方便,实则隐患明显:
- 不用 eval "$cmd" 直接执行未加引号的变量 —— 空格、分号、管道符会被误解析
- 不依赖 $() 或 `` 在拼接中嵌套执行,除非结果已做白名单校验
- 不把 PATH、IFS 等关键环境变量当作普通变量参与拼接
- 不为了“省一行”牺牲可读性:一个复杂
eval往往不如拆成两三个明确步骤


















