2

In some case, quotes can solve a param which contains space.

$ command "param 1" "param 2" ...

And it can also work for for loop.

$ for v in a "b c" "d e"
do
    echo "|$v|"
done
|a|
|b c|
|d e|

But when I use a variable after in, it not working:

$ var='a "b c" "d e"'
$ echo $var
  a "b c" "d e"
$ for v in $var
  do
      echo "|$v|"
  done
 |a|
 |"b|
 |c"|
 |"d|
 |e"|

It not working. How do I resolve this problem ?

2

2 Answers 2

5

That is why arrays were invented:

$ var=(a "b c" "d e")
$ for v in "${var[@]}"; do echo "|$v|"; done
|a|
|b c|
|d e|

Discussion

Consider:

var='a "b c" "d e"'

The problem with the above is that, once you quote a quote, it loses its magic. The double-quotes inside the single-quoted string above are characters, just like any other characters: they no longer bind anything together. That is why the output looks like this:

|a|
|"b|
|c"|
|"d|
|e"|

Reading arrays from the terminal

Arrays can be entered in newline-separated form using readarray:

$ readarray -tn3 var
a 
b c
d e
$ for v in "${var[@]}"; do echo "|$v|"; done
|a|
|b c|
|d e|

-n3 limits the input to three lines. -t tells readarray to discard the newline character.

Sign up to request clarification or add additional context in comments.

3 Comments

But how to covert a string to array ? I want to use read -p to get string args. Like this: read -p "Please input some args: " str; var=($str) ; But it not working.
@FengYu Once the quotes are in str, unfortunately, their magic has been lost. bash does provide readarray for getting arrays from the terminal. See the example in the updated answer.
Thanks. But I want to use a single line input. So that I can drag and drop a batch of files to the terminal, so that the terminal will auto add the quotes if the path contains space, and use space to split each files.
0

As mentioned in comments and another answer, use an array if you can. That really is the best option.

If you are forced to work with strings (for some odd reason not described in your question) change your internal field separator, and then use your custom defined one to separate fields.

#Copy the current IFS
SaveIFS=$IFS
IFS=';'

var='a;b c;d e;'
for v in $var; do
    echo $v
done

#Revert when done
IFS=$SaveIFS

1 Comment

I think replace IFS is not a good solution. It will affect other command.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.