Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to iterate through string one word at a time in zsh

How do I modify the following code so that when run in zsh it expands $things and iterates through them one at a time?

things="one two"

for one_thing in $things; do
    echo $one_thing
done

I want the output to be:

one 
two

But as written above, it outputs:

one two

(I'm looking for the behavior that you get when running the above code in bash)

like image 650
Rob Bednark Avatar asked Apr 18 '14 15:04

Rob Bednark


People also ask

How do you iterate through a string?

For loops with strings usually start at 0 and use the string's length() for the ending condition to step through the string character by character. String s = "example"; // loop through the string from 0 to length for(int i=0; i < s. length(); i++) { String ithLetter = s.

How do you iterate through a bash script?

We can iterate over the array elements using the @ operator that gets all the elements in the array. Thus using the for loop we iterate over them one by one. We use the variable ${variable_name[@]} in which, the curly braces here expand the value of the variable “s” here which is an array of strings.


4 Answers

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?

like image 94
devnull Avatar answered Oct 13 '22 04:10

devnull


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.

like image 36
bgdnlp Avatar answered Oct 13 '22 06:10

bgdnlp


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."

like image 29
Kevin Avatar answered Oct 13 '22 04:10

Kevin


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.

like image 3
Atttacat Avatar answered Oct 13 '22 04:10

Atttacat