I can create an associative array and assign an integer to a key that contains a single quote in it:
The single quote in key name is causing the parser to treat it as a un-terminated quote character. One way to fix this would be to escape the ' character in the key
key="john's"
printf -v escKey "%q" "$key"
now because of the %q specifier, printf() would have applied required escapes to all shell meta characters i.e. making it "shell-quoted" and re-usable. If you print the contents of escKey you'll notice the ' escaped
printf '%s\n' "$escKey"
john\'s
Now you can use this keyname in your associative array. Remember you can always manually add the escapes which could be messy. Since %q is a native way provided by the shell, it is much safe to use it.
(( dict["$escKey"]++ ))
Also in bash versions >= 4.4 parameter expansion has @Q which is a shortcut for %q specifier of printf() using which you can do
(( dict["${key@Q}"]++ ))
Turn off multiple evaluation* of associative array subscripts with following command and it'll work.
shopt -s assoc_expand_once
* An example showing the default behavior and assoc_expand_once's effect:
$ v1=42 $ v2='$v1' $ declare -A foo $ foo[$v2]= $ declare -p foo declare -A foo=(["\$v1"]="") $ (( foo[$v2]++ )) $ declare -p foo declare -A foo=([42]="1" ["\$v1"]="") $ $ shopt -s assoc_expand_once $ (( foo[$v2]++ )) $ declare -p foo declare -A foo=([42]="1" ["\$v1"]="1")