Associative arrays are local by default

后端 未结 5 1680
故里飘歌
故里飘歌 2021-02-01 14:50

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() {
    decla         


        
相关标签:
5条回答
  • 2021-02-01 15:03

    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.

    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)
    
    0 讨论(0)
  • 2021-02-01 15:10

    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.

    Thank you Greg! However Debian Squeeze still has Bash 4.1.5

    0 讨论(0)
  • 2021-02-01 15:10

    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.

    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
    }
    

    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.
    0 讨论(0)
  • 2021-02-01 15:13

    This example declares a global associative array variable inside a function, in 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
    

    Tested on GNU bash, version 4.4...

    Important notes.
    The declare -A command doesn't actually create an associative array immediately; 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 (!!!).

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

    0 讨论(0)
  • 2021-02-01 15:21

    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.

    f() {
       map[y] = foo
    }
    
    declare -A map
    foo
    echo "${map[y]}"
    
    0 讨论(0)
提交回复
热议问题