Search code examples
bashassociative-arraysubstitution

Substition in Bash and associative array


I want to dynamically declare and unset associative array, but arrays drive me crazy and they do have the best driving licence. :-(

names=( Charlie Snoopy Linux Marcia )
intestines=$(printf "%s\n" ${names[@]} | awk '{ print "["$1"]="FNR  }' | tr "\n" " ")
echo $intestines # ok: [Charlie]=1 [Snoopy]=2 [Linux]=3 [Marcia]=4
unset namesAssociative
declare -A namesAssociative=( [Charlie]=1 [Snoopy]=2 [Linux]=3 [Marcia]=4 ) # works ok 
echo ${namesAssociative[Linux]} # OK: 3 

But:

unset namesAssociative
declare -A namesAssociative=( $intestines ) # error
exec "declare -A namesAssociative=( $intestines )" # error
declare -A namesAssociative=( $(printf "%s\n" ${names[@]} | awk '{ print "["$1"]="FNR  }' | tr "\n" " ") ) # error
etc...

I guess God punishes me that I have not written that in Python from the very begining... :-)


Solution

  • This works as you expect and is made safe using the %q format indicator for the associative array's keys.

    #!/usr/bin/env bash
    
    names=( Charlie Snoopy Linux Marcia )
    
    # shellcheck disable=SC2155 # Intended dynamic declaration
    declare -A namesAssociative="($(
      for i in "${!names[@]}"; do
        printf '[%q]=%d ' "${names[i]}" $((i + 1))
      done
    ))"
    
    
    declare -p namesAssociative
    

    or Alternatively if your names array is not sparse:

    declare -A namesAssociative="($(
      i=1
      for k in "${names[@]}"; do
        printf '[%q]=%d ' "$k" $((i++))
      done
    ))"