7

I'm trying to build an associative array in a function from a list pass in via an arg, but It just isn't working:

#!/usr/bin/env bash



function cwd {
  echo "$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )"
}


function list_commands {
  local root="$1"
  local command_list="${*:2}"
  declare -A cmds
  for cmd in $command_list; do
    cmds["#{$cmd}"]+="$root/scripts/displays/$cmd.sh #{pane_current_path} #{pane_id}"
  done
  echo "$cmds"
}

PLUGIN_ROOT_DIR="$(cwd)"

declare -A cmds=$(list_commands "$PLUGIN_ROOT_DIR" "rbenv_ruby_ver githud")

main "$cmds"

I'm not sure what to do, bash scripting isn't my strong suit (though I'm getting better at it)

what can I do to make this work?

Bear in mind this will be executed in tmux as part of a tpm tmux plugin.

Thermatix
  • 351
  • 4
  • 14
  • Command argument lists are flat lists of strings, so there's no "passing" of arrays. Is `main` something that could see the variable? Is there a textual argument format it would accept and understand? Note that you can't just `echo "$cmds"` either (try it), so it's already falling over by then anyway. – Michael Homer Aug 11 '18 at 23:57
  • @MichaelHomer, I'm aware of the second point, that's why I'm asking for help, and `main`, atm is just a function that (should) printout the associative array by iterating over it, but it's not important hence why it's not in the code I posted. – Thermatix Aug 12 '18 at 00:06
  • It's quite important. Even more so, what are you trying to do with it in the end – what's the final goal? There may be a way to get where you're aiming by a different route if we know what that is. You can [edit] your question with more details. – Michael Homer Aug 12 '18 at 00:10

1 Answers1

14

Data structures other than strings can't really be passed around between shell functions. However, you may use name references to pass names of associative arrays (or of whatever other variable you may want). Name references are available in bash since release 4.3.

Example:

foo () {
    declare -n aarr="$1"

    aarr["fookey"]=foovalue
}

declare -A myarray

myarray["mainkey"]=mainvalue
foo myarray

for key in "${!myarray[@]}"; do
    printf '%s = %s\n' "$key" "${myarray[$key]}"
done

Note that bash requires that the name of the name reference variable (aarr above) is not the same as the name of the referenced variable (myarray above).

Testing:

$ bash script.sh
fookey = foovalue
mainkey = mainvalue
Kusalananda
  • 320,670
  • 36
  • 633
  • 936
  • 1
    Thanks, whilst it does require me to declare my aa outside of the function and then pass it in to modify, it dos work and do what I need it to. that and I can't give the reference in the function the same name as the one outside the function – Thermatix Aug 12 '18 at 08:26
  • @Thermatix You could also use global variables if the function is always going to act on the same variable. With a name reference variable in the function, you get the ability to call it with different associative arrays from elsewhere though. – Kusalananda Aug 12 '18 at 08:33