I thought the following would group the output of my_command
in an array of lines:
IFS='\n' array_of_lines=$(my_command);
so that $array_of_lines[1]
would refer to the first line in the output of my_command
, $array_of_lines[2]
to the second, and so forth.
However, the command above doesn't seem to work well. It seems to also split the output of my_command
around the character n
, as I have checked with print -l $array_of_lines
, which I believe prints elements of an array line by line. I have also checked this with:
echo $array_of_lines[1]
echo $array_of_lines[2]
...
In a second attempt, I thought adding eval
could help:
IFS='\n' array_of_lines=$(eval my_command);
but I got the exact same result as without it.
Finally, following the answer on List elements with spaces in zsh, I have also tried using parameter expansion flags instead of IFS
to tell zsh how to split the input and collect the elements into an array, i.e.:
array_of_lines=("${(@f)$(my_command)}");
But I still got the same result (splitting happening on n
)
With this, I have the following questions:
Q1. What are "the proper" ways of collecting the output of a command in an array of lines?
Q2. How can I specify IFS
to split on newlines only?
Q3. If I use parameter expansion flags as in my third attempt above (i.e. using @f
) to specify the splitting, does zsh ignore the value of IFS
? Why didn't it work above?
Best Answer
TL, DR:
First mistake (→ Q2):
IFS='\n'
setsIFS
to the two characters\
andn
. To setIFS
to a newline, useIFS=$'\n'
.Second mistake: to set a variable to an array value, you need parentheses around the elements:
array_of_lines=(foo bar)
.This would work, except that it strips empty lines, because consecutive whitespace counts as a single separator:
You can retain the empty lines except at the very end by doubling the whitespace character in
IFS
:To keep trailing empty lines as well, you'd have to add something to the command's output, because this happens in the command substitution itself, not from parsing it.
(assuming the output of
my_command
doesn't end in a non-delimited line; also note that you lose the exit status ofmy_command
)Note that all the snippets above leave
IFS
with its non-default value, so they may mess up subsequent code. To keep the setting ofIFS
local, put the whole thing into a function where you declareIFS
local (here also taking care of preserving the command's exit status):But I recommend not to mess with
IFS
; instead, use thef
expansion flag to split on newlines (→ Q1):Or to preserve trailing empty lines:
The value of
IFS
doesn't matter there. I suspect that you used a command that splits onIFS
to print$array_of_lines
in your tests (→ Q3).