How to export an associative array (hash) in bash?
Asked Answered
T

5

19

Related, but not a duplicate of: How to define hash tables in Bash?

I can define and use a bash hash, but I am unable to export it, even with the -x flag. For example, the following works to export (and test exportation of) a normal string variable:

aschirma@graphics9-lnx:/$ export animal_cow="moo"
aschirma@graphics9-lnx:/$ bash -c "echo \$animal_cow"
moo
aschirma@graphics9-lnx:/$ 

However, if I try to export a hash:

aschirma@graphics9-lnx:/$ declare -A -x animals
aschirma@graphics9-lnx:/$ animals[duck]="quack"
aschirma@graphics9-lnx:/$ echo ${animals[duck]}
quack
aschirma@graphics9-lnx:/$ bash -c "echo \${animals[duck]}"

aschirma@graphics9-lnx:/$ 

It seems the nested bash shell does not have the hash in its scope. I did verify this also by manually entering the nested bash shell and attempting to use the hash interactively.

Towardly answered 17/10, 2012 at 22:57 Comment(1)
If your use can accept wrapping it in GNU Parallel, you can use env_parallel: gnu.org/software/parallel/env_parallel.htmlPansophy
O
7

There isn't really a good way to encode an array variable into the environment. See http://www.mail-archive.com/[email protected]/msg01774.html (Chet Ramey is the maintainer of bash)

Otisotitis answered 17/10, 2012 at 23:9 Comment(1)
Going a little deeper, the environment is defined by the operating system; shells just provide a way to populate the environment. POSIX (to use as an example) does not provide a definition for structured data for its environment variables; each value is simply a string. Any attempt by bash to convert an array (regular or associative) to a single string would be specific to bash. That creates a portability nightmare, as the environment is no longer simply defined by the operating system, but by whatever method any user might decide to use to launch a program.Anthropologist
P
6

As a workaround for this harsh Bash limitation I'm using "serialize to temporary file" method. You can export plain variables, so you can pass an array (associative) through filepath. Of course, this has limitations, but sometimes works and is good enough.

declare -A MAP # export associative array                                                                           
MAP[bar]="baz"                                                                        
declare -x serialized_array=$(mktemp) # create temporary variable 
# declare -p can be used to dump the definition 
# of a variable as shell code ready to be interpreted                                       
declare -p MAP > "${serialized_array}" # serialize an array in temporary file 

# perform cleanup after finishing script                                      
cleanup() {                                                                   
  rm "${serialized_array}"                                                    
}                                                                             
trap cleanup EXIT   

# ... in place where you need this variable ...
source "${serialized_array}" # deserialize an array                         
echo "map: ${MAP[@]}" 
Pox answered 23/3, 2019 at 18:23 Comment(1)
Instead of manually creating and deleting the file you could use process substitution: DEF_MAP=<(declare -p map) bash -c 'source "$DEF_MAP"; # do something with map'. Here, bash -c is just a placeholder for the command to which you want to export your array.Aileenailene
S
2

Parent:

declare -A -x animals
animals[duck]="quack"
export animals_export=$(declare -p animals)

Child:

source <(printf "%s" "$animals_export")
echo ${animals[duck]}
Socialminded answered 8/3, 2024 at 14:12 Comment(0)
K
0

This is a bit old but I answer anyway, you could use temp files. If you do it right you can wrapper it to use them like arrays. For example with this function:

var() { #  set var or add comtent
    case $1 in 
    *=|*=*) 
        local __var_part1=$( echo "$1" | sed -e 's/=.*//' -e 's/[+,-]//' ) # cut +=/=
        local __var_part2=$( echo "$1" | sed -e 's/.*.=//' )
        local __var12=$tmp_dir/$__var_part1
        mkdir -p ${__var12%/*} #create all subdirs if its an array
        case $1 in 
        *+=*)
                # if its an array try to add new item
            if [ -d $tmp_dir/$__var_part1 ] ; then
            printf  -- $__var_part2 > $tmp_dir/$__var_part1/\  $(( 
                $( echo $tmp_dir/$__var_part2/* \
                    | tail  | basename )\ + 1 ))
            else
            printf -- "$__var_part2" >> $tmp_dir/$__var_part1  
            fi
            ;;
        *-=*) false ;;
            # else just add content
            *)  printf  -- "$__var_part2" > $tmp_dir/$__var_part1 ;;
        esac
        ;;  
    *) # just print var
        if [ -d $tmp_dir/$1 ] ; then
        ls $tmp_dir/$1
        elif [ -e $tmp_dir/$1 ] ; then 
        cat $tmp_dir/$1
        else
        return 1
        fi
        ;;
    esac    
}

# you can use mostly like you set vars in bash/shell
var test='Hello Welt!'
# if you need arrays set it like this:
var fruits/0='Apple'
var fruits/1='Banana'

# or if you need a dict:
var contacts/1/name="Max"
var contacts/1/surname="Musterman"

This not the fastest way, but its very flexible, simple and works in nearly all shells.

Knowledgeable answered 18/6, 2013 at 20:6 Comment(0)
K
0

short answer --> export animals after declaring it

full --> Try this way as a script:

#!/usr/bin/env bash

declare -A -x animals
export animals
animals[duck]="quack"
echo ${animals[duck]}
bash -c "echo ${animals[duck]}"

Output on my side using Bash version: 5.1.16(1)

quack
quack

or in terminal:

$ declare -A -x animals
$ export animals
$ animals[duck]="quack"
$ echo ${animals[duck]}
quack
$ bash -c "echo ${animals[duck]}"
quack
$
Kapor answered 15/4, 2022 at 15:27 Comment(3)
Wow, not even a single upvote for this? This one worked for me in zsh without all the hassle of creating a temp file etc.Cristionna
doesnt declare -x already export itStair
${animals[duck]} is expanded in the parent shell because of the double quoting. If this worked, it should still work with single quotes, or with declare -p animals instead of echo ${animals[duck]}, but it doesn't, so this answer isn't correct for Bash.Assentation

© 2022 - 2025 — McMap. All rights reserved.