After thoroughly searching for a way to create an associative array in bash, I found that declare -A array
will do the trick. But the problem is, it is only for bash version 4 and the bash version the server has in our system is 3.2.16.
How can I achieve some sort of associative array-like hack in bash 3? The values will be passed to a script like
ARG=array[key]; ./script.sh ${ARG}
EDIT: I know that I can do this in awk, or other tools but strict bash is needed for the scenario I am trying to solve.
Declaring an Associative Array and Initialize It A quick alternative is to declare and initialize an array in a single bash command as follows: $ declare -A ArrayName=( [key1]=Value1 [key2]=Value2 [Key3]=Value3…. )
Bash, however, includes the ability to create associative arrays, and it treats these arrays the same as any other array. An associative array lets you create lists of key and value pairs, instead of just numbered values.
You have two ways to create a new array in bash script. The first one is to use declare command to define an Array. This command will define an associative array named test_array. In another way, you can simply create Array by assigning elements.
Bash 3 has no associative arrays, so you're going to have to use some other language feature(s) for your purpose. Note that even under bash 4, the code you wrote doesn't do what you claim it does: ./script.sh ${ARG}
does not pass the associative array to the child script, because ${ARG}
expands to nothing when ARG
is an associative array. You cannot pass an associative array to a child process, you need to encode it anyway.
You need to define some argument passing protocol between the parent script and the child script. A common one is to pass arguments in the form key=value
. This assumes that the character =
does not appear in keys.
You also need to figure out how to represent the associative array in the parent script and in the child script. They need not use the same representation.
A common method to represent an associative array is to use separate variables for each element, with a common naming prefix. This requires that the key name only consists of ASCII letters (of either case), digits and underscores. For example, instead of ${myarray[key]}
, write ${myarray__key}
. If the key is determined at run time, you need a round of expansion first: instead of ${myarray[$key]}
, write
n=myarray__${key}; echo ${!n}
For an assignment, use printf -v
. Note the %s
format to printf
to use the specified value. Do not write since that would treat printf -v "myarray__${key}" %s "$value"
$value
as a format and perform printf %
expansion on it.
printf -v "myarray__${key}" %s "$value"
If you need to pass an associative array represented like this to a child process with the key=value
argument representation, you can use ${!myarray__*}
to enumerate over all the variables whose name begins with myarray__
.
args=() for k in ${!myarray__*}; do n=$k args+=("$k=${!n}") done
In the child process, to convert arguments of the form key=value
to separate variables with a prefix:
for x; do if [[ $x != *=* ]]; then echo 1>&2 "KEY=VALUE expected, but got $x"; exit 120; fi printf -v "myarray__${x%%=*}" %s "${x#*=}" done
By the way, are you sure that this is what you need? Instead of calling a bash script from another bash script, you might want to run the child script in a subshell instead. That way it would inherit from all the variables of the parent.
Here is another post/explanation on associative arrays in bash 3 and older using parameter expansion:
https://stackoverflow.com/a/4444841
Gilles' method has a nice if
statement to catch delimiter issues, sanitize oddball input ...etc. Use that.
If you are somewhat familiar with parameter expansion:
http://www.gnu.org/software/bash/manual/html_node/Shell-Parameter-Expansion.html
To use in your scenario [ as stated: sending to script ]: Script 1: sending_array.sh
# A pretend Python dictionary with bash 3 ARRAY=( "cow:moo" "dinosaur:roar" "bird:chirp" "bash:rock" ) bash ./receive_arr.sh "${ARRAY[@]}"
Script 2: receive_arr.sh
argAry1=("$@") function process_arr () { declare -a hash=("${!1}") for animal in "${hash[@]}"; do echo "Key: ${animal%%:*}" echo "Value: ${animal#*:}" done } process_arr argAry1[@] exit 0
Method 2, sourcing the second script: Script 1: sending_array.sh
source ./receive_arr.sh # A pretend Python dictionary with bash 3 ARRAY=( "cow:moo" "dinosaur:roar" "bird:chirp" "bash:rock" ) process_arr ARRAY[@]
Script 2: receive_arr.sh
function process_arr () { declare -a hash=("${!1}") for animal in "${hash[@]}"; do echo "Key: ${animal%%:*}" echo "Value: ${animal#*:}" done }
References:
Passing arrays as parameters in bash
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With