Bash:迭代变量名 [英] Bash: Iterate over variable names

查看:46
本文介绍了Bash:迭代变量名的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在编写一个 bash 脚本来分析一些文件.在第一次迭代中,我为所分析的每个类别创建了带有字数统计的关联数组.这些类别是事先未知的,因此这些关联数组的名称是可变的,但都具有相同的前缀 count_$category.关联数组有一个词作为关键字,它在该类别中的出现次数作为值.

I'm writing a bash script to analyse some files. In a first iteration I create associative arrays with word counts for each category that is analysed. These categories are not known in advance so the names of these associative arrays are variable but all with the same prefix count_$category. The associative arrays have a word as key and its occurrence count in that category as value.

分析完所有文件后,我必须总结每个类别的结果.我可以使用 ${count_*} 迭代变量名,但是如何访问这些变量名后面的关联数组?对于每个关联数组(每个 count_* 变量),我应该遍历单词及其计数.

After all files are analysed, I have to summarise the results for each category. I can iterate over the variable names using ${count_*} but how can I access the associative arrays behind those variable names? For each associative array (each count_* variable) I should iterate over the words and their counts.

我已经尝试过这样的间接访问,但它不起作用:

I have already tried with indirect access like this but it doesn't work:

for categorycount in ${count_*} # categorycount now holds the name of the associative array variable for each category
do
    array=${!categorycount}
    for word in ${!array[@]}
    do
        echo "$word occurred ${array[$word]} times"
    done
done

推荐答案

现代(bash 4.3+)方法使用namevars",这是从 ksh 借来的工具:

The modern (bash 4.3+) approach uses "namevars", a facility borrowed from ksh:

for _count_var in "${!count_@}"; do
    declare -n count=$_count_var                  # make count an alias for $_count_var
    for key in "${!count[@]}"; do                 # iterate over keys, via same
        echo "$key occurred ${count[$key]} times" # extract value, likewise
    done
    unset -n count                                # clear that alias
done

declare -n count=$count_var 允许使用 "${count[foo]}" 在名为 count_var 的关联数组;类似地, count[foo]=bar 将分配给相同的项目.unset -n count 然后移除这个映射.

declare -n count=$count_var allows "${count[foo]}" to be used to look up item foo in the associative array named count_var; similarly, count[foo]=bar will assign to that same item. unset -n count then removes this mapping.

在 bash 4.3 之前:

Prior to bash 4.3:

for _count_var in "${!count_@}"; do
  printf -v cmd '_count_keys=( "${!%q[@]}" )' "$_count_var" && eval "$cmd"
  for key in "${_count_keys[@]}"; do
    var="$_count_var[$key]"
    echo "$key occurred ${!var} times"
  done
done

注意使用%q,而不是直接将变量名代入字符串,生成eval的命令.尽管在这种情况下我们可能是安全的(因为可能的变量名称集受到限制),但遵循这种做法可以减少确定间接扩展是否安全所需的上下文量.

Note the use of %q, rather than substituting a variable name directly into a string, to generate the command to eval. Even though in this case we're probably safe (because the set of possible variable names is restricted), following this practice reduces the amount of context that needs to be considered to determine whether an indirect expansion is secure.

在这两种情况下,请注意内部变量(_count_var_count_keys 等)使用的名称与 count_* 模式不匹配.

In both cases, note that internal variables (_count_var, _count_keys, etc) use names that don't match the count_* pattern.

这篇关于Bash:迭代变量名的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆