zsh: How to declare associative array programmatically? - zsh

To declare associative array programmatically, I tried this:
foo=bar
typeset -A "${foo}"=(
[key1]="hello world"
[key2]=baz
)
Whatever I try, I'm getting:
zsh: unknown sort specifier
How to declare an associative array using a variable to set its name ?

This might not be the best way, but you can use indirect parameter expansion after declaring the name to be an associative array.
foo=bar
typeset -A "${(p)foo}"
typeset "${(p)foo}[hello]=world"
You can also use set -A
foo=bar
set -A $foo hello world

Related

zsh - how does the indexing for this associative array work?

The code below seems to be working correctly:
#!/bin/zsh
zparseopts -D -E -A opts f -foo
if [[ -n ${opts[(ie)-f]} || -n ${opts[(ie)--foo]} ]]; then
echo "foo is set."
else
echo "foo is not set."
fi
~/tmp > ./args.sh
foo is not set.
~/tmp > ./args.sh -f
foo is set.
~/tmp > ./args.sh --foo
foo is set.
What does the syntax for the index of opts mean i.e. (ie)-f? Is there some documentation where I can learn more about this? I don't even know what to search for to learn more about this kind of indexing.
My bad - I found it in the zsh manual here. It's explained in section 5.4.2 Using Associative Arrays.
To explain, it seems like this is a part of parameter substitutions in zsh. I don't know if it applies to bash as well.
This allows you to use certain "parameters" to perform some functionalities.
The syntax is to include the parameters within parentheses and prefix the specific part of the object that you want to substitute, modify etc.
For example, taking opts in my question,
echo ${opts}
prints the values of the associative array.
We have the parameter k which signifies the keys and v which signifies values. This can be used as follows:
echo ${(k)opts} # print only the keys
echo ${(kv)opts} # print the keys and values
To answer the main part of my question, what does (ie)-f mean, these are parameters that apply to the index of the associative array. Looking at the manual I had linked to, here is what i does - it searches for the key and returns the key instead of the value.
Explanation from the manual:
If instead of an ordinary subscript you use a subscript preceded by the flag (i), the shell will search for a matching key (not value) with the pattern given and return that. This is deliberately the same as searching an ordinary array to get its key (which in that case is just a number, the index), but note this time it doesn't match on the value, it really does match, as well as return, the key
And with regards to e - this seems a bit more complicated. But reading through the manual, it seems like this further evaluates the value if necessary i.e. in the event that it's not a constant.
Here is an example:
bar=4
foo='$bar'
> echo $foo
$bar
> echo ${(e)foo}
4
So combining the two together (ie) in my question returns the key and also expands it if necessary.

jq doesn't work with keys which contains dash in it from a variable

If you'd like jq to escape dashes, you need to put your key between square brackets like this;
jq '.["key-key"]'
and apart from that, if you'd like to include a variable in jq, you need to use double quotes instead of single quotes;
jq "."${var[i+1]}""
but my variable contains dash in it and in this case, I've tried to merge the 2 examples above but it didn't work;
var=key-key
jq ".["${var[i+1]}"]."key""
how can I get this work?
Update:
This is the final script, which I've forgot to mention;
declare -a var=(
"key-key"
"key2-key2"
"key3-key3"
)
for ((i=0; i<${#var[#]})); do
curl -s "url" | jq ".["${var}"]."something""
done
To have double-quotes in a jq command you've enclosed in double-quotes, you'd escape them with a backslash :
jq ".[\"key-key\"]"
Another problem with your final command is that ${var[i+1]} expands to the empty string, because this syntax is used to index elements of an array, and you previously defined var as a simple string.
A better way to work with variables in jq commands is to define them through the --arg name value option, after which you can refer to them with $foo in a single-quotes enclosed command :
jq --arg keyName key-key '.[$keyName]'
To fix the code included in the update, I would use the following :
declare -a var=(
"key-key"
"key2-key2"
"key3-key3"
)
json=$(curl -s "url")
for searchedKey in "${var[#]}"; do
echo $json | jq --arg keyName $searchedKey '.[$keyName].something'
done

zsh: `declare -p` associative array does not print values

run-help typeset says:
-p [ n ]
If the -p option is given, parameters and values are
printed in the form of a typeset command with an assign-
ment, regardless of other flags and options. Note that
the -H flag on parameters is respected; no value will be
shown for these parameters.
Note it says parameters and values above.
If it do:
% typeset -p ZPLGM
typeset -A ZPLGM
Note no key-values above, however they do exist:
% echo $ZPLGM[PLUGINS_DIR]
/home/ravi/.config/zsh/.zplugin/plugins
Why doesn't typeset -p work as I expect?
How do I get typeset to print a statement which, when executed, would recreate the array?
Because the variable ZPLGM is defined with -H option.
unset foo
typeset -AH foo=([bar]=123)
# ^----here
echo $foo[bar]
typeset -p foo
123
typeset -A foo
typeset has an option -H, as the manual explains:
-H Hide value: specifies that typeset will not display the
value of the parameter when listing parameters; the dis-
play for such parameters is always as if the `+' flag had
been given. Use of the parameter is in other respects
normal, and the option does not apply if the parameter is
specified by name, or by pattern with the -m option.
This is on by default for the parameters in the
zsh/parameter and zsh/mapfile modules. Note, however,
that unlike the -h flag this is also useful for non-spe-
cial parameters.
unset foo
typeset -A foo=([bar]=123)
echo $foo[bar]
typeset -p foo
123
typeset -A foo=( [bar]=123 )

bad set of key/value pairs for associative array for custom completion

I am trying to follow Make zsh complete arguments from a file but with a command. Shouldn't matter much.
In /usr/local/share/zsh/site-functions/_foo I have
#compdef foo
aliases=($(a complicated command here printing everything twice))
_describe aliases aliases
The command when ran alone prints this:
foo foo bar bar this this that that
This seems to create an associative array just fine. When I add echo ${(kv)aliases} before the _describe aliases aliases command and run /usr/local/share/zsh/site-functions/_foo I am getting
foo foo bar bar this this that that
And when I just do ${(k)aliases} then
foo bar this that
I do not really a description so this would work for me. But, it doesn't work for zsh.
I added
function foo() { echo $* }
autoload _foo
compdef _foo foo
to ~/.zshrc and after . ~/.zshrc when I type foo [tab] I get _foo:2: bad set of key/value pairs for associative array. I tried changing the command to only print everything once. Same results. I tried changing the command to print "foo:x " for every foo. Same results. So what about should my program produce for this to work?
aliases already exists as an associative array containing all your shell aliases. Call the variable something else.
It may alias help to declare your variable local, for a normal array:
local -a compl_aliases
The bad set of key/value pairs usually indicates that you have an odd number of elements when doing an associative array assignment. There needs to be an even number with a value for each key.

How to add to an associative array in zsh?

I'm trying to change an element of a zsh associative array, but I can't find any clues on the correct syntax.
The PHP equivalent would be
$assoc['key'] = 'newvalue';
but how can I do this in zsh?
The documentation seems to be very confusing on this, as it assumes that once you've set up an associative array, you never want to change it.
EDIT: this is what I'm trying to do
% noglob ZSH_HIGHLIGHT_STYLES[globbing]='fg=yellow'
zsh: command not found: ZSH_HIGHLIGHT_STYLES[globbing]=fg=yellow
$ZSH_HIGHLIGHT_STYLES is defined by the zsh-syntax-highlighting plugin.
It's actually pretty simple, assuming you have an associative array.
typeset -A assoc
assoc[key]=newvalue

Resources