如何分配按名称传递给函数的数组

tel*_*ina 7 arrays bash

我想创建一个迭代数组并插入给定值的函数(如果尚未包含它).我在我的代码的两个不同部分使用此函数,因此我必须使用不同的数组.因此我将数组名称传递给函数.现在我无法弄清楚如何分配数组的插槽来存储元素在这个地方.

这是我的代码:

name=("hello" "world")

function f {
    array_name=$2[@]
    array=("${!array_name}")
    length=${#array_name[@]}
    for (( i = 0; i <= $length; i++ )); do
        if [[ "${array[i]}" = "$1" ]];
            break;
        fi
        if [[ "$i" = "$length" ]]; then
            ${2[$length+1]=$1};
        fi
    done
}

f "test" "name"
Run Code Online (Sandbox Code Playgroud)

编辑:我希望数组附加给定的值,就像这样

for i in ${name[@]}
do
    echo $i
done
Run Code Online (Sandbox Code Playgroud)

会有这个输出:

hello
world
test
Run Code Online (Sandbox Code Playgroud)

但显然"${2[$length+1]=$1}"不起作用.

(传递数组的想法是从这里:bash如何将数组作为参数传递给函数)

gni*_*urf 6

如果我理解正确,你想要一个值附加到一个数组,如果这个值还没有在数组中,但棘手的部分是数组名称传递给该函数.

方法1

一种可能性是从不同的角度看问题:您可以将要插入的值和完整数组传递给函数,该函数将设置一个在执行后将恢复的全局变量.对于我们的测试示例,我们将使用:

array=( hello world "how are you today?" )
Run Code Online (Sandbox Code Playgroud)

我们将尝试插入testhello(因此hello不会插入):

f() {
# This function will set the global variable _f_out to an array obtained from
# the positional parameters starting from position 2, with $1 appended if and
# only if $1 doesn't appear in the subsequent positional parameters
    local v=$1 i
    shift
    _f_out=( "$@" )
    for i; do [[ $i = $v ]] && return; done
    _f_out+=( "$v" )
}
Run Code Online (Sandbox Code Playgroud)

我们来使用它:

$ array=( hello world "how are you today?" )
$ f test "${array[@]}"
$ array=( "${_f_out[@]}" )
$ printf '%s\n' "${array[@]}"
hello
world
how are you today?
test
$ f hello "${array[@]}"
$ array=( "${_f_out[@]}" )
$ printf '%s\n' "${array[@]}"
hello
world
how are you today?
test
Run Code Online (Sandbox Code Playgroud)

有用.

备注.我用过for i; do.这是一个很好的捷径for i in "$@"; do.

方法2

你真的想摆弄simili-pointers并做到附加(这不是真正的Bash精神 - 这就是为什么它有点笨拙).该工具是使用printf-v选择:来自help printf:

-v var    assign the output to shell variable VAR rather than
          display it on the standard output
Run Code Online (Sandbox Code Playgroud)

好处是它也适用于数组字段.

警告:您可能会看到其他使用的方法eval.像瘟疫一样避免它们!

f() {
    local array_name=$2[@] i
    local array=( "${!array_name}" )
    for i in "${array[@]}"; do [[ $i = $1 ]] && return; done
    # $1 was not found in array, so let's append it
    printf -v "$2[${#array[@]}]" '%s' "$1"
}
Run Code Online (Sandbox Code Playgroud)

让我们试一试:

$ array=( hello world "how are you today?" )
$ f test array
$ printf '%s\n' "${array[@]}"
hello
world
how are you today?
test
$ f hello array
$ printf '%s\n' "${array[@]}"
hello
world
how are you today?
test
Run Code Online (Sandbox Code Playgroud)

它也有效.

注意.使用这两种方法,您可以非常轻松地获得return函数的代码,例如,0如果值已插入(成功),并且1(如果值已经存在(或反过来)则失败) - 适应性很简单并且保留为练习.这在方法1中可能很有用,可以确定是否需要更新array返回值_f_out.在这种情况下,您甚至可以稍微修改,f以便_f_out在值已经在数组中时甚至不设置.

警告.在所示的两种方法中,我假设您的数组具有从0开始的连续索引(即,非稀疏数组).我认为这是一个安全的假设; 但如果不是这样,那么这些方法就会被破坏:第一个方法将(在重新分配后)将数组转换为非稀疏方法,第二个方法可能会覆盖字段(因为,对于数组a,${#a[@]}扩展为数字数组中的元素,而不是数组中找到的最高索引+ 1).