【问题标题】:BASH: Duplicate array and pass array by valueBASH:复制数组并按值传递数组
【发布时间】:2015-01-06 06:48:47
【问题描述】:

假设我有一个如下所示的数组foo,请注意第三个元素。

foo=("a" "b" "c c")
echo "${foo[2]}" # "c c"
echo "${#foo[@]}" # "3"

如何将该数组的精确副本创建到变量bar 中? 然后如果你想将该数组(按值)传递给函数baz

编辑:将答案移至答案。

【问题讨论】:

  • 您想用eval 完成什么? (为什么你认为你需要eval 来完成那件事?)
  • baz "${foo[@]}" 是按值传递数组的公认和常规方式,这使得您的值可以在函数内部以"$@" 的形式访问。您实际上所做的根本不是通过值传递,而是通过名称——也就是说,通过引用传递。
  • ...此外,特别是对于 Bash 4.3 或更高版本,有更好、更安全的方法来进行传递引用,而不涉及 eval
  • @CharlesDuffy 如果我对baz "${foo[@]}"的理解正确,这意味着没有其他参数可以传递给函数?
  • 正确,除非您有创意。例如,您可以在数组的 之前传递数组 length,然后只从 argv 中弹出那么多项。

标签: arrays bash pass-by-value


【解决方案1】:

如果你想通过 reference 传递一个数组(这是你的代码实际所做的),bash 4.3 允许使用 namevars 来完成:

foo=( hello "cruel world" )

print_contents() {
  local -n array=$1
  printf '%q\n' "${array[@]}"
}

print_contents foo

如果你想通过 value 传递,更简单(即使是旧版本也可以使用):

foo=( hello "cruel world" )

print_contents() {
  printf '%q\n' "$@"
}

print_contents "${foo[@]}"

如果要按值传递多个数组,则相反:

foo=( hello "cruel world" )
bar=( more "stuff here" )

print_arrays() {
  while (( $# )); do
    printf '%s\n' "Started a new array:"
    local -a contents=()
    local array_len
    array_len=$1; shift
    for ((n=0; n<array_len; n++)); do
      contents+=( "$1" ); shift
    done
    printf '  %q\n' "${contents[@]}"
  done
}

print_arrays "${#foo[@]}" "${foo[@]}" \
             "${#bar[@]}" "${bar[@]}"

【讨论】:

    【解决方案2】:

    我最终在写问题时找到了答案。这是思路。

    下面的几次尝试

    bar=foo           # String "foo"
    bar=$foo          # First element of array foo "a"
    
    bar=${foo[@]}
    echo "${#bar[@]}" # "1"
    echo "${bar[0]}"   # "a b c c"
    
    bar=(${foo[@]})
    echo "${#bar[@]}" # "4"
    echo "${bar[2]}"   # "c"
    echo "${bar[3]}"   # "c"
    
    bar=("${foo[@]}")
    echo "${#bar[@]}" # "3"
    echo "${bar[2]}"   # "c c"
    
    
    
    
    baz () {
      eval "bar=(\"\${$1[@]}\")"
    
      for item in "${bar[@]}"
      do
        echo "$item"
      done
    
      # a
      # b
      # c c
    }
    

    【讨论】:

    • 仅供参考——您的baz 并未声明bar 本地,因此它实际上是在修改global 变量bar,而不是将其范围限定为您的函数。
    • ...另外,我不清楚这是如何“按值”的——您传入的 $1 是变量的名称——一个引用——而不是它的值。
    【解决方案3】:
    function baz {
      set $1[@]
      printf '%s\n' "${!1}"
    }
    foo=(a b 'c c')
    bar=("${foo[@]}")
    baz bar
    

    【讨论】:

      猜你喜欢
      • 2017-06-22
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2015-08-03
      • 1970-01-01
      • 2014-01-10
      • 2012-12-02
      • 2014-09-08
      相关资源
      最近更新 更多