TL, DR:
array_of_lines=("${(@f)$(my_command)}")
First mistake (→ Q2): IFS='\n'
sets IFS
to the two characters \
and n
. To set IFS
to a newline, use IFS=$'\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:
IFS=$'\n' array_of_lines=($(my_command))
You can retain the empty lines except at the very end by doubling the whitespace character in IFS
:
IFS=$'\n\n' array_of_lines=($(my_command))
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.
IFS=$'\n\n' array_of_lines=($(my_command; echo .)); unset 'array_of_lines[-1]'
(assuming the output of my_command
doesn't end in a non-delimited line; also note that you lose the exit status of my_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 of IFS
local, put the whole thing into a function where you declare IFS
local (here also taking care of preserving the command's exit status):
collect_lines() {
local IFS=$'\n\n' ret
array_of_lines=($("$@"; ret=$?; echo .; exit $ret))
ret=$?
unset 'array_of_lines[-1]'
return $ret
}
collect_lines my_command
But I recommend not to mess with IFS
; instead, use the f
expansion flag to split on newlines (→ Q1):
array_of_lines=("${(@f)$(my_command)}")
Or to preserve trailing empty lines:
array_of_lines=("${(@f)$(my_command; echo .)}")
unset 'array_of_lines[-1]'
The value of IFS
doesn't matter there. I suspect that you used a command that splits on IFS
to print $array_of_lines
in your tests (→ Q3).
Yes, your interpretation is correct (from skimming your long question).
Parameter expansion flags apply to parameter expansions. When you want it applied to any arbitrary string instead, you need to either store that string in a variable as in:
var=%1N
filename=${(%)var}
Or (as a hack) you can use the ${var:-string}
parameter expansion and leave the var
part empty: ${(%):-%1N}
. That's a common trick(see 1
2
3
4
5
6
7
8
9
10
11
12
13 here for instance), though that makes for pretty illegible code. Alternatively, you could use the ${param+string}
syntax and use a parameter like $-
or $0
or $#
that is always set (${(%)-+%1N}
). That's neither shorter nor more legible though.
Here, you can also use print -P %1N
Best Answer
I think you are looking for
:-
parameter substitution:From man zsh:
Actually you can make this example a little bit shorter: