在Bash中对数组参数进行间接参数扩展

5

当参数是一个数组时,如何扩展参数?

如果参数是一个简单的变量,我们可以使用感叹号进行间接引用。

single_fruit()
{
    if [ "$#" != 1 ]; then exit 1; fi
    echo ${!1}
}

MYVAR=Persimmon
single_fruit MYVAR

我希望您能够将数组参数的操作与直接迭代数组元素的操作区分开来:
FRUIT=(Papaya Pineapple)
for f in ${FRUIT[@]}
do
    echo ${f}
done

我想在一个函数中进行迭代:

multi_fruit()
{
    if [ "$#" != 1 ]; then exit 1; fi
    PARAMETER=${1}
    for i in ${!PARAMETER[@]}
    do
        echo ${i}
    done
}

MOREFRUITS=(Mango Melon)
multi_fruit MOREFRUITS

你能将这个最后一个函数迭代到数组元素上吗?

下面给出了三个有用且不同的解决方案。我接受了需要最简单函数调用的一个,并点赞了其他两个。 - Calaf
3个回答

5

你可以这样做,但是方法有些出乎意料:占位符变量需要包括数组的索引:

multi_fruit() { 
    (( $# != 1 )) && return 1
    tmp="${1}[@]"
    for i in "${!tmp}"; do
        echo "$i"
    done
}

此外,仅使用大写变量名是一个不好的想法。有一天你会意外覆盖PATH并想知道为什么你的脚本出了问题。请将大写变量留给系统。

还要注意,将花括号放在变量周围并不等同于双引号。例如,请考虑:

var="one two three"
printf "%s\n" ${var}
printf "%s\n" "$var"

写"${1}[@]"的意思是我们只是简单地附加字面上的[@]。随后,扩展发生在数组名称上,而字面上的[@]被携带。这就是正在发生的事情吗? - Calaf
是的,没错。不幸的是,bash开发人员过载了${!...} -- 当应用于数组时,它会给你数组索引declare -A x=([foo]=bar [baz]=qux); echo ${!x[@]} 输出 foo baz(以某种顺序)-- 对于“标量”变量,它执行间接寻址:因此 ${!tmp} - glenn jackman

2

在BASH中传递数组并不是一件简单的事情。实际上,数组甚至没有被导出到子shell中。要将数组变量传递给函数,您需要使用"ARRAY[@]"语法,然后在函数内部使用变量间接操作符重构数组。

考虑以下脚本:

multi_fruit() {
    if [ "$#" != 1 ]; then exit 1; fi
    # array reconstructions
    arr=("${!1}")
    for i in ${arr[@]}
    do
        echo ${i}
    done
}

MOREFRUITS=(Mango Melon)
multi_fruit "MOREFRUITS[@]"

输出:

Mango
Melon

2
这可以运行:
multi_fruit()
{
    if [ $# -lt 1 ]; then exit 1; fi
    for i in "$@"
    do
        echo ${i}
    done
}

MOREFRUITS=(Mango Melon)
multi_fruit "${MOREFRUITS[@]}"

有趣..我仍在尝试解析关于$@特殊参数的bash手册页面所说的内容。 - Calaf
未加引号的 $@$* 完全相同。几乎总是特殊的引用行为导致您使用 $@,因此您应始终使用引号:"$@"。当不加引号时,请使用 $* 提供线索表明您有意将其未加引号。 - chepner

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