bash 关联数组默认是本地的

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/10806357/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-09-18 02:24:16  来源:igfitidea点击:

Associative arrays are local by default

bashscope

提问by davide

Associative arrays seem to be local by default when declared inside a function body, where they should be global. The following code

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

#!/bin/bash

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

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

produces the output:

产生输出:

x:  y:

while this

而这

#!/bin/bash

declare -A map

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

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

produces the output:

产生输出:

x: a y: b


Is it possible to declare a global associative array within a function? Or what work-around can be used?

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

采纳答案by davide

From: Greg Wooledge
Sent: Tue, 23 Aug 2011 06:53:27 -0700
Subject: Re: YAQAGV (Yet Another Question About Global Variables)

bash 4.2 adds "declare -g" to create global variables from within a function.

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

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

Thank you Greg! However Debian Squeeze still has Bash 4.1.5

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

回答by jordanm

You have already answered your own question with declare -g. The workaround on bash versions < 4.2 is to declare the array outside of the function.

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

f() {
   map[y] = foo
}

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

回答by memeplex

Fine, 4.2 adds "declare -g" but it's buggy for associative arrays so it doesn't (yet) answer the question. Here's my bug report and Chet's confirmation that there's a fix scheduled for the next release.

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

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

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

But I've serendipitously found a workaround, instead of declaring the array and assigning an initial value to it at the same time, first declare the array and then do the assignment. That is, don't do this:

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

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

but this instead:

但这反而是:

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

回答by it3xl

This example declares a global associative array variable inside a function, in bash.

此示例在 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[]=OPPA
}

do_work aa

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

Tested on GNU bash, version 4.4...

在 GNU bash 版本 4.4 上测试...

Important notes.
The declare -Acommand doesn't actually create an associative arrayimmediately; it just sets an attribute on a variable name which allows you to assign to the name as an associative array. The array itself doesn't exist until the first assignment (!!!).

重要笔记。
declare -A命令实际上并没有立即创建关联数组;它只是在变量名称上设置一个属性,允许您将名称分配为关联数组。直到第一次赋值 (!!!) 时,数组本身才存在。

(I wanted to see a complete working example in this thread, sorry.)

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

回答by Blaf

For those who are stuck with Bash version < 4.2 and are not comfortable with proposed workarounds I share my custom implementation of global associative arrays. It does not have the full power of bash associative arrays and you need to be careful about special characters in array index, but gets job done.

对于那些坚持使用 Bash 版本 < 4.2 并且对建议的解决方法不满意的人,我分享了我对全局关联数组的自定义实现。它没有 bash 关联数组的全部功能,您需要小心数组索引中的特殊字符,但可以完成工作。

get_array(){
   local arr_name=""
   local arr_key=""

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

set_array(){
   local arr_name=""
   local arr_key=""
   local arr_value=""

   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
}

Few notes:

几点注意事项:

  • Array name and array key could be combined into a single value, but split proved convenient in practice.
  • __as a separator can by hacked by malicious or careless use -- to be on the safe side use only single-underscore values in array name and key, on top of only using alphanumeric values. Of course the composition of the internal variable (separators, prefix, suffix...) can be adjusted to application and developer needs.
  • The default value expansion guarantees that undefined array key (and also array name!) will expand to null string.
  • Once you move to version of bash where you are comfortable with builtin associative arrays, these two procedures can be used as wrappers for actual associative arrays without having to refactor whole code base.
  • 数组名和数组键可以合并为一个值,但实践证明 split 很方便。
  • __作为分隔符可能会被恶意或粗心的使用所破解——为了安全起见,除了仅使用字母数字值外,在数组名称和键中仅使用单下划线值。当然,内部变量的组成(分隔符、前缀、后缀...)可以根据应用程序和开发人员的需要进行调整。
  • 默认值扩展保证未定义的数组键(以及数组名称!)将扩展为空字符串。
  • 一旦您迁移到对内置关联数组感到满意的 bash 版本,这两个过程就可以用作实际关联数组的包装器,而无需重构整个代码库。