Bash 4.2中不使用nameref实现哈希表间接引用的方法
适配Bash 4.2的关联数组间接引用方案
问题背景
原本在Bash 4.4环境中,通过declare -n(名称引用)实现关联数组的间接引用,编写了批量安装软件包的脚本:包信息存在packages.config的关联数组中,install_package函数通过nameref处理哈希表,配合install.sh循环完成批量安装。现在需要适配RHEL7自带的Bash 4.2版本(该版本不支持declare -n),普通间接引用尝试失败,需实现同等功能。
原代码示例:
packages.config
declare -A package_a=([name]="utility-blah" [ver]="2.4.1") declare -A package_b=([name]="tool-bleh" [ver]="1.3.9") # ... 更多包定义
functions.config(Bash 4.4版本)
function install_package() { declare -n package="$1" if dpkg --list ${package[name]}; then echo "${package[name]} is installed" else dpkg -i $pathToPackages/${package[name]}_${package[ver]}.deb fi }
install.sh
source packages.config source functions.config declare -a packageList=("package_a" "package_b" "package_d") for package in ${packageList[@]}; do install_package $package done
解决方案:用eval实现关联数组间接访问
Bash 4.2支持关联数组,但不支持nameref,可以通过eval命令构造变量名来间接读取关联数组的键值。修改install_package函数如下:
修改后的functions.config(适配Bash 4.2)
function install_package() { local pkg_name="$1" # 通过eval获取关联数组的name和ver字段值 local pkg_realname=$(eval "echo \${${pkg_name}[name]}") local pkg_ver=$(eval "echo \${${pkg_name}[ver]}") if dpkg --list "$pkg_realname"; then echo "$pkg_realname is installed" else dpkg -i "$pathToPackages/${pkg_realname}_${pkg_ver}.deb" fi }
核心说明
eval会解析构造的变量名:${${pkg_name}[name]}中,外层的${}会被eval展开,先替换pkg_name为实际的关联数组名(比如package_a),最终变成${package_a[name]}来获取对应值。- 变量前加
\是为了避免在eval执行前被过早展开,确保eval处理时才解析正确的变量结构。 - 给变量加上双引号,可避免文件名或包名含空格时出现解析错误。
替代方案:重构数据结构
如果不想依赖eval,可以把包信息改成普通数组的嵌套结构,降低复杂度:
修改后的packages.config
# 每个包用普通数组存储[name, ver] package_a=("utility-blah" "2.4.1") package_b=("tool-bleh" "1.3.9") # ...
对应的install_package函数
function install_package() { local pkg_array="$1" local pkg_realname=$(eval "echo \${${pkg_array}[0]}") local pkg_ver=$(eval "echo \${${pkg_array}[1]}") if dpkg --list "$pkg_realname"; then echo "$pkg_realname is installed" else dpkg -i "$pathToPackages/${pkg_realname}_${pkg_ver}.deb" fi }
内容的提问来源于stack exchange,提问作者bobe
相关产品推荐
相关产品推荐

