Bash doesn't parse quotes when converting a string to arguments

arguments, bash, quoting, spaces, string

Solution

The reason this happens is because of the order in which the shell parses the command line: it parses (and removes) quotes and escapes, then replaces variable values. By the time `$test` gets replaced with `One "This is two" Three`, it's too late for the quotes to have their intended effect.

The simple (but dangerous) way to do this is by adding another level of parsing with `eval`:

$ test='One "This is two" Three'
$ eval "set -- $test"
$ echo "$2"
This is two

(Note that the quotes in the `echo` command are not necessary, but are a good general practice.)

The reason I say this is dangerous is that it doesn't just go back and reparse for quoted strings, it goes back and reparses everything, maybe including things you didn't want interpreted like command substitutions. Suppose you had set

$ test='One `rm /some/important/file` Three'

...`eval` will actually run the `rm` command. So if you can't count on the contents of `$test` to be "safe", do not use this construct.

BTW, the right way to do this sort of thing is with an array:

$ test=(One "This is two" Three)
$ set -- "${test[@]}"
$ echo "$2"
This is two

Unfortunately, this requires control of how the variable is created.

Problem

This is my problem. In bash 3: ``` $ test='One "This is two" Three' $ set -- $test $ echo $2 "This ``` How to get bash to understand the quotes and return $2 as `This is two` and not `"This`? Unfortunately I cannot alter the construction of the variable called `test` in this example.

Original source