使用Bash传递关联数组作为参数

4
什么是将关联数组作为参数传递给函数的最佳方法,以避免重复迭代多个关联数组?这样我就可以给函数任何我选择的数组进行打印。以下是我的代码示例:
# Snippet

declare -A weapons=(
  ['Straight Sword']=75
  ['Tainted Dagger']=54
  ['Imperial Sword']=90
  ['Edged Shuriken']=25
)

print_weapons() {
  for i in "${!weapons[@]}"; do
    printf "%s\t%d\n" "$i" "${weapons[$i]}"
  done
}

print_weapons

1
你看过这个网址吗:https://dev59.com/BW855IYBdhLWcg3w7pGg#8879444? - Florian Feldhaus
4个回答

19
你可以使用 local -n 用于引用。
 declare -A weapons=(
 ['Straight Sword']=75
 ['Tainted Dagger']=54
 ['Imperial Sword']=90
 ['Edged Shuriken']=25
 )
 
 print_weapons() {
     local -n array=$1
     for i in "${!array[@]}"; do
         printf "%s\t%d\n" "$i" "${array[$i]}"
     done
 }
 
 print_weapons weapons

GNU bash版本4.2.46(x86_64-redhat-linux-gnu)上,本地选项“-n”无法正常工作:“local:-n:无效的选项”。 - Drew
1
@Drew:这是在4.3版本中添加的;请参见http://tiswww.case.edu/php/chet/bash/NEWS(它没有明确列出“local”,但“local”处理与“declare”相同的类型)。4.3版本于2014-02发布,尽管发行版不会立即选择新版本。 - dave_thompson_085
local -n - 这是魔法。 - vskubriev

8

我认为你不能将关联数组作为函数的参数传递。但是,你可以使用下面的技巧解决这个问题:

#!/bin/bash

declare -A weapons=(
  ['Straight Sword']=75
  ['Tainted Dagger']=54
  ['Imperial Sword']=90
  ['Edged Shuriken']=25
)

function print_array {
    eval "declare -A arg_array="${1#*=}
    for i in "${!arg_array[@]}"; do
       printf "%s\t%s\n" "$i ==> ${arg_array[$i]}"
    done
}

print_array "$(declare -p weapons)" 

输出

Imperial Sword ==> 90   
Tainted Dagger ==> 54   
Edged Shuriken ==> 25   
Straight Sword ==> 75   

这就是我通过一篇文章所查找的内容,而且这可能是最好的选择。非常感谢您的帮助! - theGrayFox
看起来这是从 https://dev59.com/BW855IYBdhLWcg3w7pGg#8879444 复制过来的(稍作修改);请注意,在 ${1#*=} 周围添加双引号可以解决空格问题(正如原回答中所评论的)。 - Ingo Karkat

2
使用常规数组时,使用变量间接引用已经很丑陋了,而使用关联数组更加困难——我没有找到一种迭代键的方法。
我想知道你是否需要的只是declare -p
print_array() { declare -p $1; }
print_array weapons

declare -A weapons='(["Imperial Sword"]="90" ["Tainted Dagger"]="54" ["Edged Shuriken"]="25" ["Straight Sword"]="75" )'

或者更美观一点:
print_array() { declare -p $1 | sed 's/[[)]/\n&/g'; }
print_array weapons

declare -A weapons='(
["Imperial Sword"]="90" 
["Tainted Dagger"]="54" 
["Edged Shuriken"]="25" 
["Straight Sword"]="75" 
)'

我知道我没有疯,这一点对我来说很困难。你能解释一下sed在发生什么吗? - theGrayFox
1
@Dford.py sed会在看到[(字符时添加一个新行。&将匹配项(要么是[,要么是()插入到新行中。 - jaypal singh
啊,我明白了...我得参考一下我的sed手册并学习更多的正则表达式。 - theGrayFox
我会继续尝试并看看我能得到什么。再次感谢! - theGrayFox
declare -p $1 | sed 's/[[)]/\n&/g' | sed '1d;$d' - glenn jackman
显示剩余2条评论

0
#!/bin/bash

   declare -A dict
   
   dict=(
    [ke]="va"
    [ys]="lu"
    [ye]="es" 
   ) 
   
   fun() {
     for i in $@; do
       echo $i
     done
    }
   
   fun ${dict[@]} 

# ||${dict[key]} || ${!dict[@]} || ${dict[$1]} || ${dict[@]}

1
这并不将数组键传递给函数。 - Armali
1
这是您可以传递一个键而不会出现问题的选项: 我添加了一条注释。 - Nickotine
样例对我来说是有效的。例如,fun ${dict[ke]} 会产生输出 va。我想如果你想将其用作 fun ke,那么你必须以某种方式将数组的名称传递给函数,或者使用一个可以硬编码的“明确定义”的数组名称(但这很丑陋,我猜)。祝大家好运。 - shellter
如果你想传入键,则使用 ${!dict[@]} - Nickotine
1
我同意你的帖子 ;-? ... 但是我要补充一下,有些用户可能会很懒,期望只传递关键文本,即 fun ke 就能返回值 va。但如果这是他们的目标,他们就必须增强你的函数。祝大家好运! - shellter
显示剩余2条评论

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接