Bash函数接收普通/关联数组参数异常及传递键的方法问询
如何将关联数组的键传递给使用nameref的Bash函数?
问题描述
在Apple M1最新系统的zsh终端中,编写了Bash函数run_aws_ssm_delete_parameters,使用nameref(-n)接收数组参数。传递普通索引数组时,函数能正确识别3个值;但传递关联数组的键(${!associative_array[@]})时仅识别2个值;直接传递关联数组名时,函数会传递数组的值而非键。
相关代码及运行输出如下:
原始函数与main逻辑
#!/usr/bin/env bash function run_aws_ssm_delete_parameters() { local -r enable_logging="$1" local -n parameter_names="$2" shift 2 local -a aws_cli_flags=( "delete-parameters" "--names" "${parameter_names[@]}" ) aws_cli_flags+=("$@") set -x if result="$(aws ssm "${aws_cli_flags[@]}")"; then set +x [[ "${enable_logging}" = true ]] && printf "Good: %s\n" "${result}" return 0 else set +x printf "Bad: %s" "$?" return 1 fi } function main() { local -a normal_array=("one" "two" "three") run_aws_ssm_delete_parameters true normal_array --color on local -A associative_array=( ["one"]="value_one" ["two"]="value_two" ["three"]="value_three" ) run_aws_ssm_delete_parameters true "${!associative_array[@]}" --color on } main "$@"
原始运行输出(关注--names参数)
++ aws ssm delete-parameters --names one two three --color on Unable to locate credentials. You can configure credentials by running "aws configure". + result= + set +x Bad: 0++ aws ssm delete-parameters --names three one --color on Unable to locate credentials. You can configure credentials by running "aws configure". + result= + set +x Bad: 0%
直接传递关联数组名的尝试
修改后的main函数:
function main() { local -a normal_array=("one" "two" "three") run_aws_ssm_delete_parameters true normal_array --color on local -A associative_array=( ["one"]="value_one" ["two"]="value_two" ["three"]="value_three" ) run_aws_ssm_delete_parameters true associative_array --color on } main "$@"
对应的运行输出:
++ aws ssm delete-parameters --names one two three --color on Unable to locate credentials. You can configure credentials by running "aws configure". + result= + set +x Bad: 0++ aws ssm delete-parameters --names value_two value_three value_one --color on Unable to locate credentials. You can configure credentials by running "aws configure". + result= + set +x Bad: 0%
问题分析
- 传递
${!associative_array[@]}时,Bash会直接展开为关联数组的键列表(顺序不固定),但此时传递给函数的是展开后的字符串列表而非数组引用,函数中的nameref会将其视为普通变量,导致${parameter_names[@]}无法正确识别所有元素。 - 直接传递关联数组名时,nameref引用的是关联数组本身,
${parameter_names[@]}默认会取关联数组的值而非键,这是Bash关联数组的特性。
解决方案
方法1:将关联数组的键存入普通索引数组后传递
先把关联数组的键提取到普通索引数组中,再将该数组名传递给函数,nameref即可正确识别数组所有元素:
修改后的main函数:
function main() { local -a normal_array=("one" "two" "three") run_aws_ssm_delete_parameters true normal_array --color on local -A associative_array=( ["one"]="value_one" ["two"]="value_two" ["three"]="value_three" ) # 将关联数组的键存入普通索引数组 local -a assoc_keys=("${!associative_array[@]}") # 传递这个索引数组名 run_aws_ssm_delete_parameters true assoc_keys --color on } main "$@"
方法2:修改函数以支持直接处理关联数组的键
让函数自动判断变量类型,关联数组则取键,普通数组则取元素:
修改后的函数:
function run_aws_ssm_delete_parameters() { local -r enable_logging="$1" local -n parameter_names="$2" shift 2 local -a target_elements # 判断变量是否为关联数组 if [[ "$(declare -p parameter_names 2>/dev/null)" == "declare -A"* ]]; then # 关联数组,取键 target_elements=("${!parameter_names[@]}") else # 普通数组,取元素 target_elements=("${parameter_names[@]}") fi local -a aws_cli_flags=( "delete-parameters" "--names" "${target_elements[@]}" ) aws_cli_flags+=("$@") set -x if result="$(aws ssm "${aws_cli_flags[@]}")"; then set +x [[ "${enable_logging}" = true ]] && printf "Good: %s\n" "${result}" return 0 else set +x printf "Bad: %s" "$?" return 1 fi }
此时直接传递关联数组名即可:
run_aws_ssm_delete_parameters true associative_array --color on
验证结果
两种方法修改后,运行输出中的--names参数都会正确包含三个键:
++ aws ssm delete-parameters --names one two three --color on
内容的提问来源于stack exchange,提问作者PirateApp
相关产品推荐
相关产品推荐

