37

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

#!/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

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

4

5 回答 5

34

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

bash 4.2 添加了“declare -g”来从函数中创建全局变量。

谢谢格雷格!然而 Debian Squeeze 仍然有 Bash 4.1.5

于 2012-05-29T21:14:24.077 回答
9

很好,4.2 添加了“declare -g”,但它对于关联数组来说是错误的,所以它(还没有)回答这个问题。这是我的错误报告和 Chet 确认下一个版本计划进行修复。

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)
于 2014-01-16T01:49:03.583 回答
7

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

f() {
   map[y] = foo
}

declare -A map
foo
echo "${map[y]}"
于 2012-05-29T21:18:39.940 回答
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命令实际上并没有立即创建关联数组;它只是在变量名称上设置一个属性,该属性允许您将名称作为关联数组分配给该名称。数组本身在第一次赋值 (!!!) 之前不存在。

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

于 2020-02-21T18:32:22.067 回答
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
}

几点注意事项:

  • 数组名和数组键可以组合成一个值,但实践证明拆分很方便。
  • __由于分隔符可能会被恶意或粗心使用所破坏——为了安全起见,除了仅使用字母数字值之外,在数组名称和键中仅使用单下划线值。当然,内部变量的组成(分隔符、前缀、后缀...)可以根据应用程序和开发人员的需要进行调整。
  • 默认值扩展保证未定义的数组键(以及数组名!)将扩展为空字符串。
  • 一旦您转移到您熟悉内置关联数组的 ba​​sh 版本,这两个过程就可以用作实际关联数组的包装器,而无需重构整个代码库。
于 2018-11-05T13:31:33.697 回答