How to iterate through string one word at a time in zsh
You can assume the Internal Field Separator (IFS) on bash to be \x20 (space). This makes the following work:
#IFS=$'\x20'
#things=(one two) #array
things="one two" #string version
for thing in ${things[@]}
do
echo $thing
done
With this in mind you can implement this in many different ways just manipulating the IFS; even on multi-line strings.
In order to see the behavior compatible with Bourne shell, you'd need to set the option SH_WORD_SPLIT
:
setopt shwordsplit # this can be unset by saying: unsetopt shwordsplit
things="one two"
for one_thing in $things; do
echo $one_thing
done
would produce:
one
two
However, it's recommended to use an array for producing word splitting, e.g.,
things=(one two)
for one_thing in $things; do
echo $one_thing
done
You may also want to refer to:
3.1: Why does $var where var="foo bar" not do what I expect?
You can use the z
variable expansion flag to do word splitting on a variable
things="one two"
for one_thing in ${(z)things}; do
echo $one_thing
done
Read more about this and other variable flags in man zshexpn
, under "Parameter Expansion Flags."
Another way, which is also portable between Bourne shells (sh, bash, zsh, etc.):
things="one two"
for one_thing in $(echo $things); do
echo $one_thing
done
Or, if you don't need $things
defined as a variable:
for one_thing in one two; do
echo $one_thing
done
Using for x in y z
will instruct the shell to loop through a list of words, y, z
.
The first example uses command substitution to transform the string "one two"
into a list of words, one two
(no quotes).
The second example is the same thing without echo
.
Here's an example that doesn't work, to understand it better:
for one_thing in "one two"; do
echo $one_thing
done
Notice the quotes. This will simply print
one two
because the quotes mean the list has a single item, one two
.