I am writing a zsh completion function to complete IDs from a database. There is a program listnotes
which outputs a list like this:
bf848bf6-63d2-474b-a2c0-e7e3c4865ce8 Note Title
aba21e55-22c6-4c50-8bf6-bf3b337468e2 Another one
09ead915-bf2d-449d-a943-ff589e79794a yet another "one"
...
How do I generate an associative array note_ids
from the output of the listnotes
command such that I get an associative array like this?
( bf848bf6-63d2-474b-a2c0-e7e3c4865ce8 "Note Title" aba21e55-22c6-4c50-8bf6-bf3b337468e2 "Another one" 09ead915-bf2d-449d-a943-ff589e79794a "yet another \"one\"" )
Note that there may be whitespace in the keys. I tried to generate something with sed
:
note_ids=($(listnotes | sed 's/^\(.*\) \(.*\)$/\1 "\2"/'))
but quoting strings like this doesn’t seem to work, and double quotes in the title make it even more difficult.
Try something like
typeset -A note_ids
for line in ${(f)"$(listnotes)"}; do
note_ids+=(${line%% *} ${line#* })
done
${(f)PARAM}
: split the result of the expansion of $PARAM
at newlines"$(listnotes)"
: put the output of listnotes
verbatim into the expansion.for line in LIST
: iterate over the items in LIST
as split by ${(f)…}
. note_ids+=(key value)
: add key-value pair to an the associative array note_ids
${line%% *}
: cut the largest portion matching " *"
(a space followed by anything) from the end of the expansion of line
. So remove everying after including the first space, leaving only the key.${line#* }
: cut the smallest portion matching "* "
(anything followed by three spaces) from the beginning of the expansion of $line
. So remove the key and the three spaces used as separator.Instead of using the parameter expansion flag (f)
you could also read the output of listnotes
line by line with read
:
listnotes | while read; do
note_ids+=(${REPLY%% *} ${REPLY#* })
done
Unless specified otherwise read
puts the read values into the REPLY
parameter.