Passing associative array as argument with Bash
I don't think you can pass associative arrays as an argument to a function. You can use the following hack to get around the problem though:
#!/bin/bash
declare -A weapons=(
['Straight Sword']=75
['Tainted Dagger']=54
['Imperial Sword']=90
['Edged Shuriken']=25
)
function print_array {
eval "declare -A arg_array="${1#*=}
for i in "${!arg_array[@]}"; do
printf "%s\t%s\n" "$i ==> ${arg_array[$i]}"
done
}
print_array "$(declare -p weapons)"
Output
Imperial Sword ==> 90
Tainted Dagger ==> 54
Edged Shuriken ==> 25
Straight Sword ==> 75
bash: pass associative array as a parameter to another script
If you are only calling script2.sh
from inside script1.sh
, then all you need to do (as @markp-fuso pointed out) is source script2.sh
and it will run in the current context with all the data already loaded.
If you really want it to be on the command line, then pass it as key=val
and have your code in script2.sh
check each of it's args for that format and set them in an associative array.
declare -A map=()
for arg in "$@"
do if [[ "$arg" =~ ^[A-Z]=[0-9]$ ]] # more complex k/v will get ugly
then map[${arg/=?}]=${arg/?=} # as will the assignment w/o eval
fi
done
# And finally, just to see what got loaded -
declare -p map
$: script2.sh C=3 A=1
declare -A map=([A]="1" [C]="3" )
As mentioned above, a more complicated possible set of key names and/or values will require a suitably more complex test as well as assignment logic. Clearly, for anything but the simplest cases, this is going to quickly get problematic.
Even better, set up a full getopts
loop, and pass your args with proper indicators. This takes more design and more implementation, but that's what it takes to get more functionality.
Shell script: Pass associative array to another shell script
Passing Associative array to sub script
Associative arrays and regular arrays are not well exported. But you could pass variables by using declare -p
in some wrapper call.
First script:
#!/bin/bash
declare -A cmdOptions=( [branch]=testing [function1key]=function1value
[directory]=someDir [function2key]=function2value )
declare -a someArray=( foo "bar baz" )
declare -x someVariable="Foo bar baz" # Using *export* for simple variables
bash -c "$(declare -p cmdOptions someArray someVariable);. anothershellscript.sh"
Note syntax . anothershellscript.sh
could be replaced by source anothershellscript.sh
.
Doing so, prevent need of temporary files or temporary variable and keep STDIN/STDOUT free.
Then your anothershellscript.sh
could use your variables as is.
#!/bin/bash
declare -p cmdOptions someArray someVariable
could work.
How can I update an associative array inside a function passing it by parameter?
When you use declare
in a function, you're actually making the variable local. See help declare
at a bash prompt.
Use a nameref (requires bash version 4.3+):
function update_array
{
local FILE_NAME=$1
local -n MAP=$2 # MAP is now a _reference_ to the caller's variable
# the rest stays the same
for PRICING_FIELD in $(jq -c -r '.fields[]' "${FILE_NAME}")
do
FIELD_KEY=$(jq -r '.label' <<< "${PRICING_FIELD}")
MAP["${FIELD_KEY}"]=${PRICING_FIELD}
done
}
then you simply pass the array name
declare -A PRIVATE_FIELDS
update_array "myFile.json" PRIVATE_FIELDS
declare -p PRIVATE_FIELDS
To more efficiently iterate over the JSON file:
$ jq -c -r '.fields[] | "\(.label)\t\(.)"' file.json
key1 {"label":"key1","value":"value1","other":"other1"}
key2 {"label":"key2","value":"value2","other":"other2"}
That's assuming the labels don't contain any tab characters.
Using that, plus your older bash version, you can do this
Assuming that the result arrays will be in the global scope
update_array() {
local filename=$1 varname=$2
local -A map
while IFS=$'\t' read -r label json; do
map[$label]=$json
done < <(
jq -c -r '.fields[] | "\(.label)\t\(.)"' "$filename"
)
eval declare -gA "$varname=$(declare -p map | cut -d= -f2-)"
}
You'd call it like
$ echo $BASH_VERSION
4.2.45(1)-release
$ update_array tmp/file.json myArray
$ declare -p myArray
declare -A myArray='([key2]="{\"label\":\"key2\",\"value\":\"value2\",\"other\":\"other2\"}" [key1]="{\"label\":\"key1\",\"value\":\"value1\",\"other\":\"other1\"}" )'
$ for label in "${!myArray[@]}"; do
> printf '"%s" => >>%s<<\n' "$label" "${myArray[$label]}"
> done
"key2" => >>{"label":"key2","value":"value2","other":"other2"}<<
"key1" => >>{"label":"key1","value":"value1","other":"other1"}<<
Adding to Bash associative arrays inside functions
EDIT: Found the duplicate. This is basically the same answer as this one.
You can use a reference variable for that, see help declare
:
declare [-aAfFgilnrtux] [-p] [name[=value] ...]
[...]
-n
makeNAME
a reference to the variable named by its value
[...]
When used in a function,declare
makesNAME
s local, as with thelocal
command.
f() {
declare -n paramblock="$1"
# example for reading (print all keys and entries)
paste <(printf %s\\n "${!paramblock[@]}") <(printf %s\\n "${paramblock[@]}")
# example for writing
paramblock["key 1"]="changed"
paramblock["new key"]="new output"
}
Example usage:
$ declare -A a=(["key 1"]="input 1" ["key 2"]="input 2")
$ f a
key 2 input 2
key 1 input 1
$ declare -p a
declare -A a=(["key 2"]="input 2" ["key 1"]="changed" ["new key"]="new output" )
This works very well. The only difference to an actual associative array I found so far is, that you cannot print the referenced array using declare -p
as that will only show the reference.
Passing arrays as parameters in bash
You can pass multiple arrays as arguments using something like this:
takes_ary_as_arg()
{
declare -a argAry1=("${!1}")
echo "${argAry1[@]}"
declare -a argAry2=("${!2}")
echo "${argAry2[@]}"
}
try_with_local_arys()
{
# array variables could have local scope
local descTable=(
"sli4-iread"
"sli4-iwrite"
"sli3-iread"
"sli3-iwrite"
)
local optsTable=(
"--msix --iread"
"--msix --iwrite"
"--msi --iread"
"--msi --iwrite"
)
takes_ary_as_arg descTable[@] optsTable[@]
}
try_with_local_arys
will echo:
sli4-iread sli4-iwrite sli3-iread sli3-iwrite
--msix --iread --msix --iwrite --msi --iread --msi --iwrite
Edit/notes: (from comments below)
descTable
andoptsTable
are passed as names and are expanded in the function. Thus no$
is needed when given as parameters.- Note that this still works even with
descTable
etc being defined withlocal
, because locals are visible to the functions they call. - The
!
in${!1}
expands the arg 1 variable. declare -a
just makes the indexed array explicit, it is not strictly necessary.
Related Topics
How to Program for Linux's New 'Fanotify' File System Monitoring Feature
How to Load Jna Native Support Library Elasticsearch 6.X
Linux Kernel - Add System Call Dynamically Through Module
Setup Cron Tab to Specific Time of During Weekdays
Linux Command to Delete All Files Except .Git Folder
/Usr/Bin/Perl: Bad Interpreter: Text File Busy
Add Blank Line After Every Result in Grep
Open a File Directly from a Gitlab Private Repository
Docker MACvlan Network, Unable to Access Internet
Difference Between Number in the Same Column Using Awk
Docker Behind Proxy That Changes Ssl Certificate
Curl Simple File Upload - 417 Expectation Failed
How to Test If an Address Is Readable in Linux Userspace App