填充数组在bash函数中作为参数传递

时间:2014-09-05 09:54:38

标签: arrays bash function pass-by-reference

我需要在函数内部填充数组,将其作为参数传递而不使用全局变量(该函数将在此处和不同的数组中调用)。

我已经阅读了这个讨论bash how to pass array as an argument to a function,并使用了按名称传递的解决方案,ALMOST可以解决这个问题。

这是我的代码

#!/bin/bash

function fillArray {
  arrayName=$1[@]
  array=("${!arrayName}")
  for i in 0 1 2 3
  do
    array+=("new item $i")
  done

  echo "Tot items in function: ${#array[@]}"
  for item in "${array[@]}"
  do
    echo $item
  done
  echo
}

myArray=("my item 0" "my item 1")

fillArray myArray

echo "Tot items in main: ${#myArray[@]}"
for item in "${myArray[@]}"
do
  echo $item
done

这是输出

Tot items in function: 6
my item 0
my item 1
new item 0
new item 1
new item 2
new item 3

Tot items in main: 2
my item 0
my item 1

因此,函数正确使用作为参数传递的数组(前两项是主声明中添加的项),并将新项追加到数组中。在函数调用之后,在main中,添加的项将丢失。

我错过了什么?可能是一些传递参考/传递复制的东西......

谢谢!

4 个答案:

答案 0 :(得分:2)

为了将来参考,bash 4.3:

中的命名引用变得微不足道
function fillArray {
  declare -n arrayName=$1

  for i in 0 1 2 3
  do
    arrayName+=("new item $i")
  done

  echo "Tot items in function: ${#arrayName[@]}"
  for item in "${arrayName[@]}"
  do
    echo $item
  done
  echo
}

答案 1 :(得分:1)

您正在将函数添加到函数内部的数组变量中,但数组或任何其他变量不会在BASH中作为参考传递。因此,在函数内部对这些变量所做的任何更改都不会在函数外部可见。

作为解决方法,您可以使用此示例中的全局变量:

# initialize an array
myArray=("my item 0" "my item 1")

useArrayInFunc { myArray+=("my item 2")); }

useArrayInFunc

printf "%s\n" "${myArray[@]}"
my item 0
my item 1
my item 2

答案 2 :(得分:0)

您需要将本地var分配给全局变量:

function fillArray {
  local arrayName=$1
  local ref=$arrayName[@]
  local array=("${!ref}")
  local i item key

  for i in 0 1 2 3
  do
    array+=("new item $i")
  done

  echo "Tot items in function: ${#array[@]}"
  for item in "${array[@]}"
  do
    echo $item
  done
  echo

  for key in "${!array[@]}"; do
    declare -g ${arrayName}["$key"]="${array[$key]}"
  done
}

答案 3 :(得分:0)

answer中使用这种技术。修改后,你可以

addtoarray () { var="$1"; shift 1; eval "$var+=($(printf "'%s' " "$@"))"; }

arr=('my item 0' 'my item 1')
printf "%s\n" "${arr[@]}"
echo ====
addtoarray arr 'my new item 2' 'my new item 3'
printf "%s\n" "${arr[@]}"

打印

my item 0
my item 1
====
my item 0
my item 1
my new item 2
my new item 3

也适用于初始化数组

addtoarray secarr $(seq 5)
printf "%s\n" "${secarr[@]}"

打印:

1
2
3
4
5

修改

分解函数 - 作为代码生成器

addtoarray () { var="$1"; shift 1; eval "$var+=($(printf "'%s' " "$@"))"; }
  • 函数的第一个参数是变量 name(!!!)(非值)
  • 名称(在$1中)存入$var并将其从参数中移出
  • 现在,参数仅包含数组的新元素,例如val1 val2
  • 现在构建一个bash命令:
somearrayname+=('elemnts1' 'element2' .... )
  • 其中somearrayname是我们作为第一个arg传递的变量名称
  • printf "'%s '" "$@"从arg-list
  • 创建单引号数组成员
  • 因此,如果将该函数调用为addtoarray arr val1 "spaced val2",我们会生成下一个字符串
arr+=('val1' 'spaced val2' )

这是将成员添加到名为arr的数组的正确结构 - 无论是否在争议之前,例如添加新元素到最后。 (如果它是空的,结束就是它的开始)

  • 最后eval 执行以上生成的字符串
  • 在结果中你得到了一个初始化/修改过的数组$arr($ arr是全局变量,因此在函数中也是可见的)

最后 - 残酷地偷走了@Chepner的答案;)使用他的技术addtoarray si简单如下:

addtoarray () {
    declare -n arrname=$1
    shift 1;
    arrname+=("$@")
}

如果你有bash 4.3,你应该接受@Chepner的答案 - 这是最好的。