【问题标题】:How to allocate array which is passed to a function by name如何分配按名称传递给函数的数组
【发布时间】:2014-04-22 12:44:47
【问题描述】:

我想创建一个函数,它遍历一个数组并插入给定的值,如果它还没有包含的话。我在我的代码的两个不同部分使用这个函数,所以我必须使用不同的数组。因此,我将数组名称传递给函数。现在我不知道如何分配数组的一个槽来存储这个地方的元素。

这是我的代码:

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"

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

for i in ${name[@]}
do
    echo $i
done

会有这样的输出:

hello
world
test

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

(传递数组的思路来自这里:bash how to pass array as an argument to a function

【问题讨论】:

  • 我想将我的参数1的值存储在参数2中数组的位置length+1处。
  • 有趣的问题,但缺少关键定义,需要样本输入的输出。 (请添加到上面的问题,而不是作为评论)。祝你好运。

标签: arrays bash


【解决方案1】:

如果我理解正确,如果该值尚未在数组中,则您想将值附加到数组中,但棘手的部分是 数组名称 被传递给函数。

方法一

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

array=( hello world "how are you today?" )

我们将尝试插入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" )
}

让我们使用它:

$ 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

有效。

备注。我使用了for i; do。这是for i in "$@"; do 的一个不错的快捷方式。

方法二

您真的很想摆弄 simili-pointers 并在适当的位置进行附加(这并不真正符合 Bash 的精神——这就是它有点笨拙的原因)。工具是使用printf-v 选项:来自help printf

-v var    assign the output to shell variable VAR rather than
          display it on the standard output

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

警告:您可能会看到使用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"
}

让我们试试吧:

$ 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

它也有效。

注意。 使用这两种方法,您可以很容易地获得函数的return 代码,例如,如果值被插入,0(成功),1(失败)如果值已经存在(或相反)——适应很简单,留作练习。这在方法 1 中可能很有用,可用于确定是否需要将 array 更新为返回值 _f_out。在这种情况下,您甚至可以稍微修改 f,以便当值已经在数组中时它甚至不会设置 _f_out

警告。 在显示的两种方法中,我假设您的数组具有从 0 开始的连续索引(即非稀疏数组)。我认为这是一个安全的假设;但如果不是这种情况,这些方法将被破坏:第一个将(重新分配后)将数组转换为非稀疏数组,第二个可能会覆盖字段(如数组a,@987654344 @ 扩展为数组中元素的数量,而不是数组中找到的最高索引 + 1)。

【讨论】:

  • 第一:谢谢!我认为我的观点更面向对象。我是 bash 新手,所以在理解您的代码时遇到了一些麻烦。我想要实现的是,实际上使用了我传递给函数的名称的全局数组,并且传递的值“test”被附加到它上面。我想通过替换字符串来做到这一点。据我了解,第一种方法将创建一个新的全局数组,而不是扩展我已经创建的数组。在方法 2 中,我不明白如何将值附加到数组中。我也刚刚发现您可以通过 += 而不是 array[i]= 追加。
  • @telina 在方法 2 中,附加值的行:printf -v "$2[${#array[@]}]" '%s' "$1" }:如果您的数组名称是 ary 并且有 42 个元素,"$2[${#array[@]}]" 将扩展为 ary[42]
  • @telina 您可以+= 附加到数组,但这不适用于间接,因此这里不是一个选项。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2017-07-30
  • 2011-03-25
  • 2021-12-24
  • 1970-01-01
相关资源
最近更新 更多