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.