I have to split a string and use a part of it for further processing. So the idea is:
string='aaa-bbb-ccc-ddd'
parts=(${(@s:-:)string})
print -- $parts[3]
# ccc
I would like to refactor the second and third line into one, however
print -- (${(@s:-:)string})[3]
does not work because of 'bad pattern' error. Also
print -- ${(${(@s:-:)string})[3]}
is wrong, since in this case the array expression is interpreted a flags.
Even print -- (${(@s:-:)string}) does not work. I suspect that the expression that creates the array is not evaluated in pace. Could someone please explain and point me in the right direction?
2 Answers 2
The parentheses in var=(<expr>) are really part of the assignment and not the expansion, so they are not included in a nested expression. Try this:
print -r -- ${${(s:-:)string}[3]}
#=> ccc
Note that in zsh arrays, empty unquoted values are omitted from an expansion. Empty values can be included by using quotes and the (@) parameter expansion flag:
#!/usr/bin/env zsh
# With the double dash, split[2] will be empty:
local string='aaa--bbb-ccc-ddd'
local -a split=( "${(@s:-:)string}" )
typeset -p split
#=> typeset -a split=( aaa '' bbb ccc ddd )
split=( ${(s:-:)string} )
typeset -p split
#=> typeset -a split=( aaa bbb ccc ddd )
print -r -- ${"${(@s:-:)string}"[3]}
#=> bbb
print -r -- ${${(s:-:)string}[3]}
#=> ccc
For completeness, besides ${${(s[-])string}[3]}, which splits on - to get a list and then takes the 3rd element from that list, you can use:
$ string=aaa-bbb-ccc
$ print -r - $string[(ws[-])3]
ccc
Which uses the w subscript flag to index a string word-wise instead of the default of character-wise, and the s subscript flag to specify how those words are separated.
In that case, there's however no @ flag you can use to preserve empty elements. -aa---bb-cc- has 3 and only 3 -separated words, aa, bb and cc.