problem with for loop and a variable with spaces...Hi

Hi there,

I don't understand the following behavior:

toto:~$ for word in un "deux trois"; do echo $word; done
un
deux trois
toto:~$ sentence='un "deux trois"'
toto:~$ for word in $sentence; do echo $word; done
un
"deux
trois"
toto:~$ sentence="un 'deux trois'"
toto:~$ for word in $sentence; do echo $word; done
un
'deux
trois'

Why is the word with a space split in two parts even though it is surrounded by quotes in the variable $sentence?
Is there any way to get the same behavior with a variable and with an explicit string?

Thanks for your help.
Santiago

Hi.

Unless you quote $sentence itself in your for loop, it's still just a collection of words each individually assigned to $word.

$ sentence="un 'deux trois'"
$ for word in "$sentence"; do echo "$word"; done
un 'deux trois'

... and if you quote $sentence, there's no point in using a loop, since without field splitting there will always be just one word after the parameter expansion :wink:

Quote characters stored in a variable are not special in any way. The variable's expansion occurs after the shell has identified quoted strings.

Of course :slight_smile: But I suppose if there were more than one "sentence" it would hold water!

Hi all and thanks for your cooperation.
I think I didn't express myself correctly.

What I'm expecting is to have the sentence un "deux trois" split in two words: un and deux trois.

It's easy to achieve using an explicit string. But is there any way I can do that with the sentence in a variable?

Thanks
Santiago

$ eval "for word in $sentence; do echo \$word; done"
un
deux trois

As always, eval should not be used on untrusted, unsanitized input.

Regards,
Alister

Some shells support arrays.

For example zsh, bash and ksh93 support this syntax:

sentence=(un "deux trois")
for w in "${sentence[@]}"; do
  printf '%s\n' "$w"
done

With the Bourne shell, you can use something like this (you'll loose any previously set positional parameters):

set -- un "deux trois"
for w in "$@"; do
  printf '%s\n' "$w"
done

Some shells support the following shortcut in this context:

set -- un "deux trois"
for w; do
  printf '%s\n' "$w"
done

Thanks alister, your command works fine.
Thanks also for your warning, I will be very touchy with input.

Thanks radoulov for helping but your commands does not work with the sentence in a variable.

Actually I was suggesting to use an array variable instead of scalar variable ...

Yes radoulov, you're right.
Your idea is indeed interesting but I don't think I can easily change my script commands from variable to array.
Your sed example doesn't work with a variable either but I just learned a powerfull command (set).
Thanks for your help anyway.

Hi there,

I don't know if you're still following this thread but I found a way to efficiently use both your ideas.

Because the sentence was read as a string (not an array), I had no other way than using alister's idea:

But I also had a lot of statements to put in my for loop. So it would have become a little messy:

$ eval "for word in $sentence; do action1 \$word; action2 \$word; action3 \$word; action4 \$word...; done"

At that point, radoulov's idea was interesting because it left the for loop open to any statement:

So I combined the two ideas and came up with this:

# That's how I read the sentence anyway:
sentence='un "deux trois" quatre'
# Then I turn it into an array:
eval "sentence=($sentence)"
# Et voila!
for word in "${sentence[@]}"; do
    action1 "$word"
    action2 "$word"
    action3 "$word"
    action4 "$word"
    ...
done

Thank you both!