如何将数组作为函数参数传递?


57

努力将数组作为参数传递了一段时间,但仍然无法正常工作。我已经尝试过如下所示:

#! /bin/bash

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

}

array=("one" "two" "three")

copyFiles $array

有解释的答案会很好。

编辑:基本上,我最终将从另一个脚本文件调用该函数。请尽可能解释约束条件。

Answers:


84
  • 扩展没有索引的数组只会给出第一个元素,使用

    copyFiles "${array[@]}"

    代替

    copyFiles $array
  • 使用她的爆炸

    #!/bin/bash
  • 使用正确的函数语法

    有效的变体是

    function copyFiles {…}
    function copyFiles(){…}
    function copyFiles() {…}

    代替

    function copyFiles{…}
  • 使用正确的语法获取数组参数

    arr=("$@")

    代替

    arr="$1"

因此

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

}

array=("one" "two" "three")

copyFiles "${array[@]}"

输出为(我的脚本的名称为foo

$ ./foo   
one
two
three

谢谢,但是函数copyFiles {…}不是正确的语法吗?虽然我是新手,但我使用语法成功运行了一些程序。
Ahsanul Haque 2015年

有效的变体是copyFiles {…}and copyFiles(){…}copyFiles() {…},但不是copyFiles{…}。注意不带()
AB

19

如果要传递一个或多个参数和一个数组,我建议对@AB
Array 脚本的更改应为最后一个参数,并且只能传递一个数组

#!/bin/bash
function copyFiles() {
   local msg="$1"   # Save first argument in a variable
   shift            # Shift all arguments to the left (original $1 gets lost)
   local arr=("$@") # Rebuild the array with rest of arguments
   for i in "${arr[@]}";
      do
          echo "$msg $i"
      done
}

array=("one" "two" "three")

copyFiles "Copying" "${array[@]}"

输出:

$ ./foo   
Copying one
Copying two
Copying three

2
+1以了解需要放在最后的数组,并且只应发送一个数组
David'the秃头姜

1
感谢您的shift使用。
Itachi

有时使用shift的参数也很有用,因此,如果数组前有6个参数,则可以使用shift 6
向上旋转

您将“其余参数”转换为arr。中间可以有一个数组参数吗?甚至几个数组参数?function copyAndMove() { msg1=$1 ; arr1=...?... ; msg2=? ; arr2=...?... ; msg3=? ; ... }。就像我在python:中定义它一样def copyAndMove(msg1="foo", cpFiles=[], msg2="bar", mvFiles=[], msg3="baz"): ...。没关系,我找到了stackoverflow.com/a/4017175/472245
towi

18

您也可以将数组作为参考传递。即:

#!/bin/bash

function copyFiles {
   local -n arr=$1

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

array=("one" "two" "three")

copyFiles array

但请注意,对arr的任何修改都将对array进行。


1
虽然这并不是我想要的,但是知道如何在bash中按引用传递仍然很高兴。+1 :)
Ahsanul Haque 2015年

3
需要bash
4.3+

8

有几个问题。这是工作表格:

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

}

array=("one" "two" "three")
copyFiles "${array[@]}"
  • 函数声明和之间至少要有一个空格 {

  • 您不能使用$array,因为array数组不是变量。如果要获取数组的所有值,请使用"${array[@]}"

  • 在你主函数声明你需要arr="$@""${array[@]}"将扩大到用空格隔开的索引值,如果你使用$1,你将只能得到第一个值。要获取所有值,请使用arr="$arr[@]}"


您需要arr=("$@")
AB

要查看区别,请在break下面添加echo "$i"。在您的版本中,您仍然会看到所有元素。但是,应该是三行。
AB

@heemayl:小错字-您第二个项目符号数组中的{丢失了...“ $ {array [@]}”“ ...
Cbhihe 2015年

3

以下是一个更大的示例。有关说明,请参见代码中的注释。

#!/bin/bash -u
# ==============================================================================
# Description
# -----------
# Show the content of an array by displaying each element separated by a
# vertical bar (|).
#
# Arg Description
# --- -----------
# 1   The array
# ==============================================================================
show_array()
{
    declare -a arr=("${@}")
    declare -i len=${#arr[@]}
    # Show passed array
    for ((n = 0; n < len; n++))
    do
        echo -en "|${arr[$n]}"
    done
    echo "|"
}

# ==============================================================================
# Description
# -----------
# This function takes two arrays as arguments together with their sizes and a
# name of an array which should be created and returned from this function.
#
# Arg Description
# --- -----------
# 1   Length of first array
# 2   First array
# 3   Length of second array
# 4   Second array
# 5   Name of returned array
# ==============================================================================
array_demo()
{
    declare -a argv=("${@}")                           # All arguments in one big array
    declare -i len_1=${argv[0]}                        # Length of first array passad
    declare -a arr_1=("${argv[@]:1:$len_1}")           # First array
    declare -i len_2=${argv[(len_1 + 1)]}              # Length of second array passad
    declare -a arr_2=("${argv[@]:(len_1 + 2):$len_2}") # Second array
    declare -i totlen=${#argv[@]}                      # Length of argv array (len_1+len_2+2)
    declare __ret_array_name=${argv[(totlen - 1)]}     # Name of array to be returned

    # Show passed arrays
    echo -en "Array 1: "; show_array "${arr_1[@]}"
    echo -en "Array 2: "; show_array "${arr_2[@]}"

    # Create array to be returned with given name (by concatenating passed arrays in opposite order)
    eval ${__ret_array_name}='("${arr_2[@]}" "${arr_1[@]}")'
}

########################
##### Demo program #####
########################
declare -a array_1=(Only 1 word @ the time)                                       # 6 elements
declare -a array_2=("Space separated words," sometimes using "string paretheses") # 4 elements
declare -a my_out # Will contain output from array_demo()

# A: Length of array_1
# B: First array, not necessary with string parentheses here
# C: Length of array_2
# D: Second array, necessary with string parentheses here
# E: Name of array that should be returned from function.
#          A              B             C              D               E
array_demo ${#array_1[@]} ${array_1[@]} ${#array_2[@]} "${array_2[@]}" my_out

# Show that array_demo really returned specified array in my_out:
echo -en "Returns: "; show_array "${my_out[@]}"

1

最好的方法是传递位置参数。没有其他的。您可以作为字符串传递,但是这种方式可能会引起一些麻烦。例:

array=(one two three four five)

function show_passed_array(){
  echo $@
}

要么

function show_passed_array(){
  while $# -gt 0;do
    echo $1;shift
  done
}

    show_passed_array ${array[@]}

输出:

  one two three four five

您的意思是,如果数组值具有空格符号,则必须在使用函数$ 1 $ 2 $ 3 ...位置参数通过索引访问值之前,先引用元素。其中索引0-> 1,1,1-> 2,...要迭代访问,最好始终使用$ 1并在Shift之后使用。无需任何其他操作。您可以传递没有这样的数组的参数:

show_passed_array one two three four five

bash媒体会根据传递的参数自动构建一个数组,并将其传递给函数,然后您将获得位置参数。此外,当您编写$ {array [2]}时,您实际上会写出随后的参数一二三四,并将它们传递给函数。因此,这些调用是等效的。


1

尽管很丑陋,但是只要您不显式传递数组,而是传递与数组相对应的变量,这是一种可行的解决方法:

function passarray()
{
    eval array_internally=("$(echo '${'$1'[@]}')")
    # access array now via array_internally
    echo "${array_internally[@]}"
    #...
}

array=(0 1 2 3 4 5)
passarray array # echo's (0 1 2 3 4 5) as expected

我敢肯定,有人可以提出一个更清晰的想法,但是比起将数组作为参数传递"{array[@]"}给内部然后使用进行访问,我发现这是一个更好的解决方案array_inside=("$@")。当还有其他位置/ getopts参数时,这变得很复杂。在这些情况下,我必须先确定和然后使用shift和删除数组元素的组合来删除与数组无关的参数。

一个纯粹主义者认为这种方法违反了语言,但从务实的角度来说,这种方法使我免除了很多苦恼。在一个相关的主题上,我还使用eval一个内部构造的数组来分配一个变量,该数组根据target_varname我传递给函数的参数命名:

eval $target_varname=$"(${array_inside[@]})"

那是丑陋和不必要的。如果要按名称传递数组array_internally,请为其别名:declare -n array_internally=$1。关于“变得复杂”和“确定然后删除...”的其余部分适用于不管如何传递数组,因此我不知道这是什么意思。并eval可能包含特殊字符的数组只是在等待以后发生悲伤。
muru
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.