用 ${var_name} 包裹变量最直接有效防止解析越界,因 Shell 会将紧邻的字母、数字、下划线连同 $ 一起识别为变量名,而花括号明确界定边界,配合双引号可安全处理空格与特殊字符,动态变量名需用 ${!ref} 或 declare -n。

用 ${var_name} 包裹变量,是防止解析越界最直接有效的方式。
为什么 $var_name 容易越界
Shell 解析变量时,会尽可能把紧挨着的字母、数字、下划线当作变量名的一部分。比如:
-
$user_id会被当成一个叫user_id的变量,而不是user变量加字符串_id -
$path/bin如果path未定义,就变成/bin;如果定义了但值是/opt,结果是/opt/bin——看似正常,但一旦写成$paths(多了一个 s),就会静默出错
花括号明确边界,解决所有常见越界场景
加 {} 后,Shell 严格按括号内内容识别变量名,后面紧跟的字符一律视为普通文本:
-
${user}_id→ 先取user的值,再拼上字面量_id -
${path}/bin→ 先取path的值,再加/bin,不会误读成path/这个变量 -
${name}Doe→ 正确输出JohnDoe,而$nameDoe会去找不存在的nameDoe变量
配合引号,应对空格和特殊字符
仅用 ${var} 不足以防空格问题;必须搭配双引号,才能完整保留原始内容:
- 错误:
cp $src $dst,若src="my file.txt",实际执行的是cp my file.txt $dst(两个参数) - 正确:
cp "${src}" "${dst}",确保整个值作为单个参数传递 - 拼接路径时也一样:
"${base_dir}/config.conf"比$base_dir/config.conf更安全可靠
特殊情况:变量名本身要动态生成
当变量名不是写死的,而是由其他变量拼出来的,需用间接引用或 declare,避免硬拼 eval:
- 推荐方式:
ref="${prefix}_${suffix}"; echo ${!ref}(Bash 支持) - 更清晰方式(Bash 4.3+):
declare -n alias_ref="${prefix}_${suffix}"; echo "$alias_ref" - 不推荐:
eval "echo \$$ref"或eval "echo \$$ref"—— 易受注入,且可读性差

















