关联数组默认为本地数组

时间:2012-05-29 20:36:13

标签: bash scope

当在函数体内声明时,关联数组在默认情况下似乎是本地的,它们应该是全局的。以下代码

#!/bin/bash

f() {
    declare -A map
    map[x]=a
    map[y]=b
}

f
echo x: ${map[x]} y: ${map[y]}

产生输出:

x:  y:

虽然这个

#!/bin/bash

declare -A map

f() {
    map[x]=a
    map[y]=b
}

f
echo x: ${map[x]} y: ${map[y]}

产生输出:

x: a y: b

是否可以在函数中声明全局关联数组? 或者可以使用哪种解决方法?

5 个答案:

答案 0 :(得分:23)

  

来自:Greg Wooledge
  发送时间:2011年8月23日星期二06:53:27 -0700
  主题:回复:YAQAGV(关于全局变量的另一个问题)

     

bash 4.2添加“declare -g”以从a中创建全局变量   功能

谢谢格雷格!但Debian Squeeze仍有Bash 4.1.5

答案 1 :(得分:7)

您已使用declare -g回答了自己的问题。关于bash版本的解决方法< 4.2是在函数外声明数组。

f() {
   map[y] = foo
}

declare -A map
foo
echo "${map[y]}"

答案 2 :(得分:5)

很好,4.2增加了“declare -g”,但它对于关联数组来说是错误的,所以它还没有(还)回答这个问题。这是我的错误报告,切特确认下次发布时有一个修复程序。

http://lists.gnu.org/archive/html/bug-bash/2013-09/msg00025.html

但我偶然发现了一种解决方法,而不是声明数组并同时为其分配初始值,首先声明数组然后执行赋值。也就是说,不要这样做:

declare -gA a=([x]=1 [y]=2)

但请改为:

declare -gA a; a=([x]=1 [y]=2)

答案 3 :(得分:2)

此示例在bash中的函数内部声明了一个全局关联数组变量。

set -euf +x -o pipefail # There is no place for implicit errors in this script.

function init_arrays(){
    # FYI. Multiple array declarations are not a problem. You can invoke it multiple times.

    # The "-gA" switch is the trick for the global array declaration inside a function.
    declare -gA my_var
}

function do_work(){
    init_arrays

    my_var[$1]=OPPA
}

do_work aa

echo ${my_var[aa]}
echo It is expected to get OPPA value printed above

在GNU bash 4.4版上进行了测试...

重要说明。
declare -A命令doesn't actually create an associative array立即;它只是在变量名称上设置一个属性,该属性使您可以将其作为关联数组分配给该名称。直到第一个赋值(!!!),数组本身才存在。

(抱歉,我想在此线程中看到一个完整的工作示例。)

答案 4 :(得分:0)

对于那些坚持使用Bash版本<4.2且对建议的变通方法不满意的人,我分享了我的全局关联数组的自定义实现。它没有bash关联数组的全部功能,因此您需要注意数组索引中的特殊字符,但要做好工作。

get_array(){
   local arr_name="$1"
   local arr_key="$2"

   arr_namekey_var="ASSOCARRAY__${arr_name}__${arr_key}"
   echo "${!arr_namekey_var:=}"
}

set_array(){
   local arr_name="$1"
   local arr_key="$2"
   local arr_value="$3"

   arr_namekey_var="ASSOCARRAY__${arr_name}__${arr_key}"
   if [[ -z "${arr_value}" ]]; then
      eval ${arr_namekey_var}=
   else
      printf -v "${arr_namekey_var}" "${arr_value}"
   fi
}

一些注意事项:

  • 数组名称和数组键可以组合为一个值,但实践证明拆分很方便。
  • __作为分隔符可以被恶意或粗心大意的黑客入侵-为了安全起见,仅使用字母数字值,仅在数组名称和键中使用单下划线值。当然,可以根据应用程序和开发人员的需求来调整内部变量的组成(分隔符,前缀,后缀...)。
  • 默认值扩展保证未定义的数组键(以及数组名!)将扩展为空字符串。
  • 一旦您转为使用内置关联数组的bash版本,这两个过程就可以用作实际关联数组的包装,而不必重构整个代码库。