The issue is that your command substitution expands to a whitespace-delimited string and the loop will iterate over all words in that string. A "word" is anything delimited by a space, tab or newline character.
Also note that in Bourne-like shells other than zsh
, those words are further subject to filename generation (aka globbing), so wildcard characters (and {
in some shells) would also be a problem in addition to space and tab.
lssyscfg -r lpar -m "$system" -F name,lpar_env | cut -d, -f 1 | sort |
while IFS= read -r lpar; do
echo "$lpar"
done
This uses a while
loop instead of a static for
loop. The while
loop body is executed in a subshell (in bash
), so the lpar
variable will not exist after the end of the loop body. That's not an issue if you only use the variable in the loop body though.
Related: Understanding "IFS= read -r line"
Another solution would be to set IFS
to a newline before the loop (and reset it afterwards):
oldIFS=$IFS
IFS=$'\n' # assumes bash
set -o noglob
for lpar in $( lssyscfg -r lpar -m "$system" -F name,lpar_env | cut -d, -f 1 | sort )
do
echo "$lpar"
done
set +o noglob
IFS=$oldIFS
The default value of $IFS
includes spaces, which is why your original loop iterates over the wrong things. I have also turned off filename globbing for the loop, as we otherwise might get unexpected results if the text returned from lssyscfg
includes filename globbing patterns as discussed above.
This last variation is IMHO quite inelegant, and downright inappropriate for commands that produce more than a handful of lines of output.
lssyscfg
command is as some of us don't have access to systems with that command.$()
instead of `command
`