如何将数组作为函数参数传递但带有其他额外参数?

如何将数组作为函数参数传递但带有其他额外参数?

以下帖子解决方案按预期工作:

因此 - 从他的回答来看:

function copyFiles() {
   arr=("$@")
   for i in "${arr[@]}";
      do
          echo "$i"
      done

}

array=("one 1" "two 2" "three 3")

copyFiles "${array[@]}"

写这篇文章的原因是如果发生以下情况怎么办:

copyFiles "${array[@]}" "Something More"
copyFiles "Something More" "${array[@]}"

问题:我确实意识到发送的参数,当收到它们时,函数中的参数如何 - 它们实际上是合并的 - 因此,$1$2数组”参数不再按预期工作整合与另一个论点

我已经做了一项研究:

可悲的typeset -n不是工作

并在:

不是按预期工作 - 在该答案中,有一条评论表明存在问题 - 带有演示测试/验证的链接 - 关于${#array[@]}函数内的数组大小 ( ) 不同。

那么如何实现这个目标呢?

答案1

不可能像这样传递数组作为参数。即使看起来你这样做了,但它并没有像你期望的那样工作

您的外壳(例如此处bash:)将扩展"${array[@]}"到各个项目执行函数!

所以这

copyFiles "Something More" "${array[@]}"

实际上会打电话

copyFiles "Something More" "one 1" "two 2" "three 3"

因此,在函数内部不可能将数组与其他参数区分开。

(你可以 添加对数组的引用,但我反对使用它,因为它似乎不太便携,而且如果没有必要,您也不会想要混合范围)。


您可以使用shift,例如

copyFiles() {
    var1=$1
    shift
    for i in "$@"; do ... ; done
}

(注意,这arr=("$@")是多余的,$@已经是一个数组,你甚至不需要指定"$@",你也可以使用for i; do ...; done

或用类似的东西解析参数getopts

答案2

你不能直接做到这一点,无论如何也不是很好。数组确实不是 Bash 中的一流对象,如果您需要做这样的事情,您可能需要真正考虑切换到真正的编程语言......

核心问题是"${array[@]}"只是扩展到数组的所有元素(列表)(忘记索引!),而不是实际给出数组本身。

当然有一些解决方法,但我不确定我会称它们非常好。但你可以...

  1. 使用一些分隔符:

    func "non-array" "arguments" :: "${array[@]}" 
    

    这本质上就是 GNU Parallel 所做的事情,但缺点是您需要决定一些不能用作实际参数的值。 (或者某种逃避它的方法,这可能会更糟。)您必须扫描参数列表才能找到分隔符。

  2. 添加参数来告知列表的长度:

    func 1 "non-array argument" "${#array[@]}" "${array[@]}" 
    

    这应该足够通用,可以传递任何有效值,但如果它开始让您回想起 C 中手动内存处理的痛苦回忆,我不会责怪您。在另一端解析它也可以作为任何疯狂到想要这样做的人的练习。

  3. 改为按名称传递数组。

    您可能想使用 namerefs,例如:

    fun() {
        local _arrayname="$1"
        local -n _ref="$1"
        printf "array '%s' has %d members\n" "$_arrayname" "${#_ref[@]}"
        printf "member at index #2 is '%s'\n" "${_ref[2]}"
    }
    asdf=(one too tree)
    fun asdf
    

    您也可以尝试使用${!p}间接语法,但是 IIRC,使用该语法对数组进行索引更困难。当然,两者都是不可移植的,因此您最终可能会陷入 Bash 困境,但 Bash 至少从 4.4 版本开始支持 namerefs,因此在大多数情况下这不应该成为问题。

    namerefs 的问题是命名空间冲突,您无法将名为_arrayname或的数组传递_ref给上述函数。

相关内容