-->

如何循环使用间接引用一个数组?如何循环使用间接引用一个数组?(How to iterate over

2019-06-12 05:13发布

我怎样才能让这段代码的工作?

#!/bin/bash
ARRAYNAME='FRUITS'
FRUITS=( APPLE BANANA ORANGE )
for FRUIT in ${!ARRAYNAME[@]}
do
    echo ${FRUIT}
done

此代码:

echo ${!ARRAYNAME[0]}

打印苹果 。 我tryng做类似,但与“[@]”的阵列上重复的东西。

提前致谢,

Answer 1:

${!ARRAYNAME[@]}的意思是“指数ARRAYNAME ”。 正如指出的bash手册页 ,因为ARRAYNAME设置,但作为一个字符串,而不是一个数组,则返回0

下面是一个使用的解决方案eval

#!/usr/bin/env bash

ARRAYNAME='FRUITS'
FRUITS=( APPLE BANANA ORANGE )

eval array=\( \${${ARRAYNAME}[@]} \)

for fruit in "${array[@]}"; do
  echo ${fruit}
done

什么原先尝试做的是创造一个间接引用 。 这些都是在bash版本2中引入并打算在很大程度上取代了需要eval试图实现在壳反射般的行为时。

你有什么用使用数组间接引用时做的是包括[@]在你的猜测在变量名:

#!/usr/bin/env bash

ARRAYNAME='FRUITS'
FRUITS=( APPLE BANANA ORANGE )

array="${ARRAYNAME}[@]"
for fruit in "${!array}"; do
  echo $fruit
done

所有这一切说,这是一件事在这个简单的例子来使用间接引用,但正如丹尼斯威廉姆森提供的链接表示,你应该犹豫在真实世界的脚本来使用它们。 他们所有,但保证让你的代码比必要更多的混乱。 通常你可以得到你所需要的关联数组的功能。



Answer 2:

这里有一个办法做到这一点不EVAL。

招击#2描述如下: http://mywiki.wooledge.org/BashFAQ/006

似乎在bash 3和多达工作。

#!/bin/bash

ARRAYNAME='FRUITS'
tmp=$ARRAYNAME[@]
FRUITS=( APPLE BANANA ORANGE "STAR FRUIT" )
for FRUIT in "${!tmp}"
do
    echo "${FRUIT}"
done

下面是示出如何通过参考一个函数来传递阵列的更现实的例子:

pretty_print_array () {
  local arrayname=$1
  local tmp=$arrayname[@]
  local array=( "${!tmp}" )
  local FS=', ' # Field seperator
  local var
  # Print each element enclosed in quotes and separated by $FS
  printf -v var "\"%s\"$FS" "${array[@]}"
  # Chop trailing $FS
  var=${var%$FS}
  echo "$arrayname=($var)"
}
FRUITS=( APPLE BANANA ORANGE "STAR FRUIT" )
pretty_print_array FRUITS
# prints FRUITS=("APPLE", "BANANA", "ORANGE", "STAR FRUIT")


Answer 3:

eval执行包含代码的数组元素,即使它们包含,例如,命令置换。 它也改变通过它们的bash解释元字符数组元素。

避免这些问题的工具是declare 参考 ,见man bash下宣告:

-n给每个名字的属性nameref,使其成为一个名称引用另一个变量。 其它变量由名称的值来定义。 所有参考文献,任务和属性修改名称,除非使用或更改-n属性本身的,是由名称的值引用的变量进行。 所述nameref属性不能被应用到数组变量。

#!/bin/bash
declare -n ARRAYNAME='FRUITS'
FRUITS=(APPLE BANANA ORANGE "BITTER LEMON")
for FRUIT in "${ARRAYNAME[@]}"
do
    echo "${FRUIT}"
done


Answer 4:

我只是想补充另一种有用的用例。 我在网上搜索解决一个不同的,但相关的问题

ARRAYNAME=( FRUITS VEG )
FRUITS=( APPLE BANANA ORANGE )
VEG=( CARROT CELERY CUCUMBER )
for I in "${ARRAYNAME[@]}"
do
    array="${I}[@]"
    for fruit in "${!array}"; do
        echo $fruit
    done
done


Answer 5:

尽管简单OP的问题,这些问题的答案将不能扩展为最常见,实际使用情况,即包含空格或应该还没有扩展到文件名通配符数组元素。

FRUITS=( APPLE BANANA ORANGE 'not broken' '*.h')
ARRAYNAME=FRUITS
eval ARRAY=\(\${$ARRAYNAME[@]}\)

$ echo "${ARRAY[4]}"
broken
$ echo "${ARRAY[5]}"
config.h
$

这工作:

FRUITS=( APPLE BANANA ORANGE 'not broken' '*.h')
ARRAYNAME=FRUITS
eval ARRAY="(\"\${$ARRAYNAME[@]}\")"

$ echo "${ARRAY[3]}"
not broken
$ echo "${ARRAY[4]}"
*.h
$

正如你应该使用的习惯, "$@"不是$@ ,总是引用里面( )数组扩展,除非你想文件名扩展或知道有没有包含空格的数组元素的可能性。

这样做: X=("${Y[@]}")

不这样的: X=(${Y[@]})



文章来源: How to iterate over an array using indirect reference?