Shell数组不能直接通过环境变量传递,需序列化→传递→反序列化;推荐printf %q+eval、临时文件或位置参数三种方式,避免export数组、空格分割及shell兼容性问题。

Shell 中数组不能直接通过环境变量传递给子脚本,因为标准 Shell(如 bash)的环境变量只支持字符串,不保留数组结构。在复杂嵌套脚本中传递数组,关键在于“序列化 → 传递 → 反序列化”,同时需注意作用域、引号处理和跨脚本兼容性。
用 printf %q + eval 安全序列化数组
这是最可靠的方式,尤其适合含空格、换行、特殊字符的元素:
- 父脚本中用
printf %q将数组每个元素转义成 shell 可安全解析的字符串 - 拼接成单个字符串,通过环境变量或参数传给子脚本
- 子脚本用
eval "array=($var)"恢复数组(注意:仅限信任上下文,避免用户输入)
示例:
# parent.sh
arr=( "file name" "path/with spaces" "$HOME" )
export ARR_STR=$(printf "%q " "${arr[@]}")
./child.sh
# child.sh
eval "arr=($ARR_STR)"
echo "Received ${#arr[@]} items: ${arr[*]}"
用临时文件规避环境限制
当数组很大、元素含不可控内容,或需多级子脚本继承时,临时文件更健壮:
- 父脚本将数组逐行写入
mktemp文件(用printf '%s\0'支持空字符分隔更稳妥) - 把文件路径通过环境变量或参数传给子脚本
- 子脚本用
mapfile -t或while IFS= read -r读取还原
优点是完全绕过 shell 解析边界,适合深度嵌套或混合 sh/bash 场景。
用命名参数替代全局数组
若子脚本逻辑可控,改用位置参数传递更简洁:
- 父脚本调用时直接展开数组:
./child.sh "${arr[@]}" - 子脚本用
args=("$@")接收,无需环境变量 - 对多层调用,可在中间脚本中保持
"$@"透传(加引号!)
这种方式零序列化开销,但要求子脚本不依赖环境变量,且调用链必须显式转发参数。
避免常见陷阱
很多问题源于忽略 Shell 的作用域和解析规则:
-
不要用
export arr—— 数组本身无法被导出 -
不要用
export arr="a b c"后在子脚本arr=($arr)—— 空格分割会破坏原结构 - 跨脚本时统一用
#!/bin/bash,sh 不支持数组 - 嵌套调用中,确保每层都正确引用变量:
"${arr[@]}"而非$arr

















