Reputation: 5449
I have a command that outputs a bunch of stuff e.g. running mycmd
will give:
foobar
derp derp
like so
etc
Some of these lines will have spaces in them.
How do I read these into an array in zsh such that ${arr[1]}
gives foobar
, ${arr[2]}
gives derp derp
etc.
I have tried something like but it seems to split the array on chars not newlines.
IFS=$'\n' read -d '' -r arr <<< "$(mycmd)"
i.e. ${arr[1]}
gives f
when it should give foobar
Upvotes: 11
Views: 9001
Reputation: 13853
I'm not sure exactly why the read
usage in the original question didn't work. It's possibly related to mixing <<<
and $()
. Or maybe the user just had a messed up shell session. Or maybe it was a bug in an older version of Zsh.
In any case, it has nothing to do with the behavior of the read
builtin, and the original proposal was very close to correct. The only problem was using <<< $(...)
instead of a plain pipe, which should just be a stylistic goof (rather than an error).
The following works perfectly fine in Zsh 5.8.1 and 5.9:
function mycmd {
print foobar
print derp derp
print like so
print etc
}
typeset -a lines
mycmd | IFS=$'\n' read -r -d '' -A lines
echo ${(F)lines}
You should see:
foobar
derp derp
like so
etc
I prefer this style, instead of ( $(...) )
. Not requiring a subshell is useful in many cases, and the quoting/escaping situation is a lot simpler.
Note that -d ''
is required to prevent read
from terminating at the first newline.
You can wrap this up in a function easily:
function read-lines {
if (( $# != 1 )); then
print -u2 'Exactly 1 argument is required.'
return 2
fi
local array="${1:-}"
read -r -d '' "$array"
}
Upvotes: 1