jolivier
jolivier

Reputation: 7635

Loop over set of strings containing spaces

I have multiple strings like "a b", "c d", "foo bar" and so on. I want to loop over this set of string and perform an action on each of these. In this action I call multiple other scripts so I do not want to change IFS for this loop since it could break my invocation of other scripts. This is why I try to escape the spaces contained in these strings but without success.

So for instance I expect to get

a b
c d

And I tried the following:

#!/bin/sh

x="a b"
y="c d"

echo "Attempt 1"
all="$x $y"

for i in $all ; do
  echo $i
done

echo "Attempt 2"
all="a\ b c\ d"
for i in $all ; do
  echo $i
done

echo "Attempt 3"
all=($x $y)
for i in ${all[@]} ; do
  echo $i
done

echo "Attempt 4"
all='"'$x'" "'$y'"'
for i in $all ; do
  echo $i
done

echo "Attempt 5"
for i in "$x" "$y" ; do
  echo $i
done

echo "Attempt 6"
all2=("a b" "c d");
for i in ${all2[@]}; do
  echo $i
done

echo "Attempt 7"
all3="a b c d"
echo $all3|
while read i; do
  echo $i 
done 

Only attempt 5 succeeds, but I would like to do this without having to declare one variable per string, (it would be painful to maintain). I just introduced x and y for testing but the idea is to declare in one variable the set "a b" and "c d".

Upvotes: 39

Views: 50922

Answers (2)

fedorqui
fedorqui

Reputation: 289825

You need to wrap the variables within double quotes, both in all=("$x" "$y") and "${all[@]}":

x="a b"
y="c d"

echo "Attempt XX"
all=("$x" "$y")
for i in "${all[@]}" ; do
  echo "$i"
done

Which yields:

Attempt XX
a b
c d

You can also define the strings with:

all=("a b" "c d")
for i in "${all[@]}" ; do
  echo "$i"
done

Upvotes: 42

Adrian Frühwirth
Adrian Frühwirth

Reputation: 45576

Your problem is lack of quoting. Without quoting, word splitting occurs:

$ x="a b"; y="c d"; all=("$x" "$y"); for i in "${all[@]}"; do echo "$i"; done
a b
c d

Using an array is the most elegant solution, and, of course, x and y are superfluous. You can just as well do:

$ all=("a b" "c d"); for i in "${all[@]}"; do echo "$i"; done
a b
c d

Upvotes: 9

Related Questions