【问题标题】:Dynamically name array with variable during iteration over another array in BASH在 BASH 中的另一个数组上迭代期间使用变量动态命名数组
【发布时间】:2016-07-24 14:54:57
【问题描述】:

我有一个数组

FIRST_ARRAY=(NEWYORK CALIFORNIA TEXAS)

接受一个州的脚本可以返回该州的城市

例如以下将返回:

user@localhost:~$ search NEWYORK cities
newyorkcity
buffalo
albany

user@localhost:~$ search CALIFORNIA cities
sanfrancisco 
paloalto 
losangeles

user@localhost:~$ search TEXAS cities
houston 
dallas 
austin

我想迭代 FIRST_ARRAY

for state in ${FIRST_ARRAY[@]}
   do
     cities=`search ${FIRST_ARRAY[state]} cities`
     ARRAY_$state=($cities}
done

最后,我希望已经创建了以下数组,它们将包含以下值

ARRAY_NEWYORK=(newyorkcity buffalo albany)
ARRAY_CALIFORNIA=(sanfrancisco paloalto losangeles)
ARRAY_TEXAS=(houston dallas austin)

如果这可行,那么例如,我希望能够通过以下方式调用我的动态创建的数组来访问 austin

echo ${ARRAY_TEXAS[2]}

谢谢!

【问题讨论】:

标签: arrays bash associative-array


【解决方案1】:

在 bash 4.0 或更高版本上,readarray / mapfile 可用,以下是简洁而正确的实现:

for state in "${FIRST_ARRAY[@]}"; do
    readarray -t "ARRAY_$state" < <(search "$state" cities)
done

在 bash 4.3 中,可以对代码进行安全的直译:

for state in "${FIRST_ARRAY[@]}"; do
    readarray -t cities < <(search "$state" cities)

    # make "dest" a namevar -- an alias -- for your intended destination
    # skip to next state if current state name is invalid
    # otherwise we could be assigning to an utterly different "dest"
    declare -n dest="ARRAY_$state" || continue

    # assign to that namevar
    dest=( "$cities" )

    # and discard it
    unset -n dest
done

在 bash 3.x 中,安全地执行此操作需要一些 printf %q 魔法来准备要由 eval 解析的内容:

for state in "${FIRST_ARRAY[@]}"; do

    # why this, and not array=( $cities )? Try a city with spaces in its name.
    # or look at what happens when you have a "city name" that's a wildcard.
    cities=( )
    while read -r city; do
        cities+=( "$city" )
    done < <(search "$state" cities)

    # generate eval-safe replacement for the cities array
    printf -v cities_str '%q ' "${cities[@]}"

    # extra paranoia: make sure we fail with a parse error rather than doing something
    # unexpected if the state name is not a valid shell variable
    printf -v eval_str 'ARRAY_%q=( %s )' "$state" "$cities_str"

    eval "$eval_str" # and evaluate that
done

原始问题没有提供search 的实现以使答案可测试。对于这个答案,我使用以下内容:

search() {
  case $1 in
    NEWYORK) printf '%s\n' newyorkcity buffalo albany ;;
    CALIFORNIA) printf '%s\n' sanfrancisco paloalto losangeles ;;
    TEXAS) printf '%s\n' houston dallas austin ;;
  esac
}

通过以上定义,结果可以验证如下:

$ declare -p ARRAY_NEWYORK ARRAY_CALIFORNIA ARRAY_TEXAS
declare -a ARRAY_NEWYORK='([0]="newyorkcity" [1]="buffalo" [2]="albany")'
declare -a ARRAY_CALIFORNIA='([0]="sanfrancisco" [1]="paloalto" [2]="losangeles")'
declare -a ARRAY_TEXAS='([0]="houston" [1]="dallas" [2]="austin")'

【讨论】:

  • Charles,我应该指出我使用的是 BASH 4.1,这可以为您省去很多麻烦。我提前道歉(尽管知道如何在旧情况下应用此解决方案也很方便)。 'search' 是一个查询 mongodb 的内部 cli。我可以提供一些其他信息来提供更多帮助吗?
  • 您的第一个解决方案非常成功,并且给了我想要的结果。现在我知道倒排数组是解决方案,我可以稍微阅读并更好地理解它是如何工作的。非常感谢您在如此翔实的回答中付出的时间和精力!
  • 我很抱歉——第一段中提到的“倒排数组”实际上是我最终意识到没有必要并删除的修正案的一部分。 (这将为实际映射回索引的${FIRST_ARRAY[state]} 提供替代方案,但仔细观察后我意识到该扩展可以简单地替换为$state)。
  • @ARL,...至于您可以提供的任何其他内容,我认为您可能会包含类似于 search 的实现的内容,我在以后的问题中给出了答案(当这些问题依赖在内部工具上),以便提供足够的内容让人们运行他们提出的答案并验证它们是否有效(在 MCVE 中给出的 V 在stackoverflow.com/help/mcve)。足够详细地描述行为以允许构建模拟实现就足够了(非常感谢!),但自己提供它会更好。
猜你喜欢
  • 2018-07-22
  • 2017-11-06
  • 1970-01-01
  • 1970-01-01
  • 2013-07-01
  • 1970-01-01
  • 1970-01-01
  • 2014-07-12
相关资源
最近更新 更多