Bash-使用函数修改数组

Bash-使用函数修改数组,bash,Bash,我不明白为什么这个示例脚本没有修改array2的内容。似乎我们应该能够通过迭代array1的元素并通过array2的索引将相应的元素设置为等于array1中的元素,从而将array2设置为等于array1 #!/bin/bash array1=(1 2 3) array2=() modify_array2 () { #set array2 to be equal to array1 by iterating through array1's #elements and setting th

我不明白为什么这个示例脚本没有修改array2的内容。似乎我们应该能够通过迭代array1的元素并通过array2的索引将相应的元素设置为等于array1中的元素,从而将array2设置为等于array1

#!/bin/bash

array1=(1 2 3)
array2=()

modify_array2 () {
#set array2 to be equal to array1 by iterating through array1's 
#elements and setting the corresponding element by index of array2 by 
#to be equal to the element in array1

index=0
declare -a _array1=("${!1}")
declare -a _array2=("${!2}")
for i in "${_array1[@]}"; do
  _array2["$index"]="$i"
  ((index++))
done
}

modify_array2 array1[@] array2[@]
#this should permanently modify array2, however if we print the 
#contents of array2, we get nothing:

for i in "${array2[@]}"; do
  printf "$i\n"
done
输出:

Shellcheck说:

第3行: 数组1=(1 2 3) ^--SC2034:阵列1似乎未使用。验证是否使用(如果外部使用,则导出)。 没有意义,我显然是在用它:

modify_array2 array1[@] array2[@]
第11行: _array2[“$index”]=“$i” ^--SC2034:_array2未使用。验证是否使用(如果外部使用,则导出)

奇怪,因为我不是通过在中使用位置参数展开来使用它的:

modify_array2 array1[@] array2[@]
并在中的函数中使用:

_array2["$index"]="$i"
第19行: printf“$i\n” ^--SC2059:不要在printf格式字符串中使用变量。使用printf“.%s…”“$foo”


很好,但我也尝试了echo,同样的结果

我发现您的脚本有两个问题。第一个是在
modify_array2
函数中使用两个声明的局部变量,它们是由作为参数传递的值创建的。第二个问题是永远不要修改
array2
变量

一种可能的解决办法是:

#!/bin/bash

array1=(1 2 3)
array2=()

modify_array2 () {
    #set array2 to be equal to array1 by iterating through array1's 
    #elements and setting the corresponding element by index of array2 by 
    #to be equal to the element in array1

    index=0
    local -n _array1=$1
    local -n _array2=$2
    for i in "${_array1[@]}"; do
        _array2["$index"]="$i"
        ((index++))
    done
}

printf "These are the contents of array1 before calling the function:\n"
printf "%s\n" "${array1[@]}"

printf "These are the contents of array2 before calling the function:\n"
printf "%s\n" "${array2[@]}"

modify_array2 array1 array2

printf "These are the contents of array2 after calling the function:\n"
printf "%s\n" "${array2[@]}"
我使用
local
来创建两个局部变量,而不是
declare
。这只是我个人的喜好,因为
declare
使变量在函数中使用时成为局部变量,就好像它们是使用
local
创建的一样(请参见
帮助declare

但与问题更相关的是处理传递给函数的参数的方式。在原始脚本中,它们是按值传递的。因此,不可能对参数列表中传递的第二个数组进行任何更改


在建议的解决方案中,调用函数传递数组本身(而不是数组值)。在函数内部,创建两个局部变量作为对作为参数传递给函数的数组的引用。这就是
-n
选项的含义:创建另一个变量的nameref(引用)。如果在Bash手册页中查找nameref,您将看到“nameref通常在shell函数中用于引用其名称作为参数传递给函数的变量”。这样,您对引用所做的任何赋值都被视为对作为参数传递的变量的赋值。

我发现您的脚本存在两个问题。第一个是在
modify_array2
函数中使用两个声明的局部变量,它们是由作为参数传递的值创建的。第二个问题是永远不要修改
array2
变量

一种可能的解决办法是:

#!/bin/bash

array1=(1 2 3)
array2=()

modify_array2 () {
    #set array2 to be equal to array1 by iterating through array1's 
    #elements and setting the corresponding element by index of array2 by 
    #to be equal to the element in array1

    index=0
    local -n _array1=$1
    local -n _array2=$2
    for i in "${_array1[@]}"; do
        _array2["$index"]="$i"
        ((index++))
    done
}

printf "These are the contents of array1 before calling the function:\n"
printf "%s\n" "${array1[@]}"

printf "These are the contents of array2 before calling the function:\n"
printf "%s\n" "${array2[@]}"

modify_array2 array1 array2

printf "These are the contents of array2 after calling the function:\n"
printf "%s\n" "${array2[@]}"
我使用
local
来创建两个局部变量,而不是
declare
。这只是我个人的喜好,因为
declare
使变量在函数中使用时成为局部变量,就好像它们是使用
local
创建的一样(请参见
帮助declare

但与问题更相关的是处理传递给函数的参数的方式。在原始脚本中,它们是按值传递的。因此,不可能对参数列表中传递的第二个数组进行任何更改


在建议的解决方案中,调用函数传递数组本身(而不是数组值)。在函数内部,创建两个局部变量作为对作为参数传递给函数的数组的引用。这就是
-n
选项的含义:创建另一个变量的nameref(引用)。如果在Bash手册页中查找nameref,您将看到“nameref通常在shell函数中用于引用其名称作为参数传递给函数的变量”。这样,您对引用所做的任何赋值都将被视为对作为参数传递的变量的赋值。

添加一个shebang,然后将脚本粘贴到此处:添加此,感谢添加一个shebang,然后将脚本粘贴到此处:添加此,感谢从手册中引用关于将变量声明为
nameref
的内容,这可能会使这个答案更好。谢谢,这似乎是可行的。我试图从在线文档中找到local-n的用法,因为我以前见过它,但令人惊讶的是,它似乎没有很好的文档记录。我知道传递数组的值可能是一个问题,但我还不明白本地与全局作用域是一个问题。@Fingers:see
help local
@oguzismail我添加了一个额外的段落,其中提到了Bash手册页中包含的nameref定义。@Fingers我编辑了对建议的解决方案澄清了您可以使用
local
declare
,因为
declare
在函数中使用时创建变量,就像它们是由
local
创建的一样。添加手册中关于将变量声明为
nameref
的引文可能会更好地回答这个问题,这似乎奏效了。我试图从在线文档中找到local-n的用法,因为我以前见过它,但令人惊讶的是,它似乎没有很好的文档记录。我知道传递数组的值可能是一个问题,但我还不明白本地与全局作用域是一个问题。@Fingers:see
help local
@oguzismail我添加了一个额外的段落,其中提到了Bash手册页中包含的nameref定义。@Fingers我编辑了对建议的解决方案澄清了您可以使用
local
declare
,因为
declare
在函数中使用时创建变量,就像它们是由
local
创建的一样。