【问题标题】:How to pass array as an argument to a function in Bash如何将数组作为参数传递给 Bash 中的函数
【发布时间】:2013-05-03 22:07:33
【问题描述】:

众所周知,在 bash 编程中传递参数的方式是 $1, ..., $N。但是,我发现将数组作为参数传递给接收多个参数的函数并不容易。这是一个例子:

f(){
 x=($1)
 y=$2

 for i in "${x[@]}"
 do
  echo $i
 done
 ....
}

a=("jfaldsj jflajds" "LAST")
b=NOEFLDJF

f "${a[@]}" $b
f "${a[*]}" $b

如上所述,函数f接收两个参数:第一个分配给x,它是一个数组,第二个分配给y

f 可以通过两种方式调用。第一种方式使用"${a[@]}"作为第一个参数,结果是:

jfaldsj 
jflajds

第二种方式使用"${a[*]}"作为第一个参数,结果是:

jfaldsj 
jflajds 
LAST

结果都不如我所愿。那么,有没有人知道如何在函数之间正确传递数组?

【问题讨论】:

标签: arrays bash shell


【解决方案1】:

你不能传递一个数组,你只能传递它的元素(即扩展的数组)。

#!/bin/bash
function f() {
    a=("$@")
    ((last_idx=${#a[@]} - 1))
    b=${a[last_idx]}
    unset a[last_idx]

    for i in "${a[@]}" ; do
        echo "$i"
    done
    echo "b: $b"
}

x=("one two" "LAST")
b='even more'

f "${x[@]}" "$b"
echo ===============
f "${x[*]}" "$b"

另一种可能性是按名称传递数组:

#!/bin/bash
function f() {
    name=$1[@]
    b=$2
    a=("${!name}")

    for i in "${a[@]}" ; do
        echo "$i"
    done
    echo "b: $b"
}

x=("one two" "LAST")
b='even more'

f x "$b"

【讨论】:

  • 按名称传递数组?你能说得更清楚吗?我发现你只是让它成为可能
  • @RedLv:只需传递数组的名称,并使用! 的参数扩展来获取数组。
  • 请注意,“name”变量的值仅仅是字符串“x[@]”。魔术发生在${!...}
  • @choroba 太棒了,当要调用的函数与调用者在同一个文件中时,这个想法是完美的。不幸的是,我需要将数组和其他值作为参数传递给脚本,以便通过 ssh user@host cmd 命令在远程主机中执行。您对如何使其成为可能有任何建议。顺便问一下,你有没有关于“按名称”机制的参考。
  • 请注意:按名称传递数组 => 按引用传递。被调用函数的任何变化都会改变全局值。此外,不能传递函数的局部数组。
【解决方案2】:

您可以先传递“标量”值。这会简化事情:

f(){
  b=$1
  shift
  a=("$@")

  for i in "${a[@]}"
  do
    echo $i
  done
  ....
}

a=("jfaldsj jflajds" "LAST")
b=NOEFLDJF

f "$b" "${a[@]}"

此时,你不妨直接使用数组式的位置参数

f(){
  b=$1
  shift

  for i in "$@"   # or simply "for i; do"
  do
    echo $i
  done
  ....
}

f "$b" "${a[@]}"

【讨论】:

  • 你的想法可以在这种情况下解决。但是它并没有达到将数组作为参数传递的目的。
  • 谢谢,这很好。我的服务器默认的 bash shell 版本低于 4.3,你的解决方案没问题。
  • 我喜欢这个,因为它很容易理解。适用于 4.3 以下的版本。
  • 没有,我错了,评论已删除,抱歉!
  • 别担心,我已经做过无数次了。
【解决方案3】:

这将解决将数组传递给函数的问题:

#!/bin/bash

foo() {
    string=$1
    array=($@)
    echo "array is ${array[@]}"
    echo "array is ${array[1]}"
    return
}
array=( one two three )
foo ${array[@]}
colors=( red green blue )
foo ${colors[@]}

【讨论】:

    【解决方案4】:

    您可以通过设置-n 属性将数组按名称引用传递给 bash(自 4.3+ 版起)中的函数:

    show_value () # array index
    {
        local -n myarray=$1
        local idx=$2
        echo "${myarray[$idx]}"
    }
    

    这适用于索引数组:

    $ shadock=(ga bu zo meu)
    $ show_value shadock 2
    zo
    

    它也适用于关联数组:

    $ declare -A days=([monday]=eggs [tuesday]=bread [sunday]=jam)
    $ show_value days sunday
    jam
    

    另请参阅手册页中的 namerefdeclare -n

    【讨论】:

    • 如果您的 shell 支持,则为最佳答案。最轻的代码。直截了当。谢谢:>
    • 缺点是您必须在函数中为调用中的数组使用另一个名称。
    • CentOS 7 (centos-release-7-7.1908.0.el7.centos.x86_64) 不支持这个,因为它的默认 bash 版本是 4.2.26
    • show_value 中,myarrayarray 之一可能是错字。它们可能应该是相同的名称。
    • 很好看,已修复。谢谢:)
    【解决方案5】:

    将数组作为函数传递

    array() {
        echo "apple pear"
    }
    
    printArray() {
        local argArray="${1}"
        local array=($($argArray)) # where the magic happens. careful of the surrounding brackets.
        for arrElement in "${array[@]}"; do
            echo "${arrElement}"
        done
    
    }
    
    printArray array
    

    【讨论】:

      【解决方案6】:

      这样试试

      function parseArray {
          array=("$@")
      
          for data in "${array[@]}"
          do
              echo ${data}
          done
      }
      
      array=("value" "value1")
      
      parseArray "${array[@]}"
      

      【讨论】:

        【解决方案7】:

        这是一个示例,我将 2 个 bash 数组接收到一个函数中,以及它们后面的附加参数。对于任意数量的 bash 数组任意数量的附加参数,这种模式可以无限期地继续下去,适应任何输入参数顺序,只要每个 bash 数组的长度就在该数组的元素之前。

        print_two_arrays_plus_extra_args 的函数定义:

        # Print all elements of a bash array.
        # General form:
        #       print_one_array array1
        # Example usage:
        #       print_one_array "${array1[@]}"
        print_one_array() {
            for element in "$@"; do
                printf "    %s\n" "$element"
            done
        }
        
        # Print all elements of two bash arrays, plus two extra args at the end.
        # General form (notice length MUST come before the array in order
        # to be able to parse the args!):
        #       print_two_arrays_plus_extra_args array1_len array1 array2_len array2 \
        #       extra_arg1 extra_arg2
        # Example usage:
        #       print_two_arrays_plus_extra_args "${#array1[@]}" "${array1[@]}" \
        #       "${#array2[@]}" "${array2[@]}" "hello" "world"
        print_two_arrays_plus_extra_args() {
            i=1
        
            # Read array1_len into a variable
            array1_len="${@:$i:1}"
            ((i++))
            # Read array1 into a new array
            array1=("${@:$i:$array1_len}")
            ((i += $array1_len))
        
            # Read array2_len into a variable
            array2_len="${@:$i:1}"
            ((i++))
            # Read array2 into a new array
            array2=("${@:$i:$array2_len}")
            ((i += $array2_len))
        
            # You can now read the extra arguments all at once and gather them into a
            # new array like this:
            extra_args_array=("${@:$i}")
        
            # OR you can read the extra arguments individually into their own variables
            # one-by-one like this
            extra_arg1="${@:$i:1}"
            ((i++))
            extra_arg2="${@:$i:1}"
            ((i++))
        
            # Print the output
            echo "array1:"
            print_one_array "${array1[@]}"
            echo "array2:"
            print_one_array "${array2[@]}"
            echo "extra_arg1 = $extra_arg1"
            echo "extra_arg2 = $extra_arg2"
            echo "extra_args_array:"
            print_one_array "${extra_args_array[@]}"
        }
        

        示例用法:

        array1=()
        array1+=("one")
        array1+=("two")
        array1+=("three")
        
        array2=("four" "five" "six" "seven" "eight")
        
        echo "Printing array1 and array2 plus some extra args"
        # Note that `"${#array1[@]}"` is the array length (number of elements
        # in the array), and `"${array1[@]}"` is the array (all of the elements
        # in the array) 
        print_two_arrays_plus_extra_args "${#array1[@]}" "${array1[@]}" \
        "${#array2[@]}" "${array2[@]}" "hello" "world"
        

        示例输出:

        Printing array1 and array2 plus some extra args
        array1:
            one
            two
            three
        array2:
            four
            five
            six
            seven
            eight
        extra_arg1 = hello
        extra_arg2 = world
        extra_args_array:
            hello
            world
        

        有关其工作原理的更多示例和详细说明,请在此处查看我对此主题的更长回答:Passing arrays as parameters in bash

        【讨论】:

          猜你喜欢
          • 2012-12-07
          • 2021-10-05
          • 2017-06-03
          • 2011-12-26
          • 2011-08-06
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多