How to split command’s output and assigns result to an array using only a single expression

zsh

NB: I've read the answers to other similar questions (How to split the output and store it in an array?, How to split a string into an array in bash), but none of them answer the specific question I'm asking here.


Suppose that the output of some command foo is a single line consisting of 10 tab-separated fields. Then

tmpvar=$( foo )
fields=( ${(ps:\t:)tmpvar} )
echo $#fields
# 10

Q: How can I achieve the same splitting of foo's output on tabs without needing an intermediate assignment to tmpvar?


FWIW, this does not work:

fields=( ${(ps:\t:)$( foo )} )
echo $#fields
# 1

Best Answer

$ printf '<%s>\n' "${(@ps:\t:)$(printf 'foo bar\t\tbaz')}"
<foo bar>
<>
<baz>

Or if you do want to suppress the empty elements like in your tempvar approach:

$ printf '<%s>\n' ${(ps:\t:)"$(printf 'foo bar\t\tbaz')"}
<foo bar>
<baz>

IOW, you need to quote the command substitution. Otherwise the s:\t: applies on the joining (with the first character of $IFS) of the fields resulting of the $IFS-splitting of the command substitution.

Alternatively, you could set $IFS to the empty string or to a single non-whitespace character.

$ (IFS=; printf '<%s>\n' ${(ps:\t:)$(printf 'foo bar\t\tbaz')})
<foo bar>
<baz>