Why does shell ignore quoting characters in arguments passed to it through variables?

bash, expansion, quoting, syntax, variables

Solution

Why

When the string is expanded, it is split into words, but it is not re-evaluated to find special characters such as quotes or dollar signs or ... This is the way the shell has 'always' behaved, since the Bourne shell back in 1978 or thereabouts.

Fix

In `bash`, use an array to hold the arguments:

argumentArray=(-ir 'hello world')
grep "${argumentArray[@]}" .

Or, if brave/foolhardy, use `eval`:

argumentString="-ir 'hello world'"
eval "grep $argumentString ."

On the other hand, discretion is often the better part of valour, and working with `eval` is a place where discretion is better than bravery. If you are not completely in control of the string that is `eval`'d (if there's any user input in the command string that has not been rigorously validated), then you are opening yourself to potentially serious problems.

Note that the sequence of expansions for Bash is described in Shell Expansions in the GNU Bash manual. Note in particular sections 3.5.3 Shell Parameter Expansion, 3.5.7 Word Splitting, and 3.5.9 Quote Removal.

Problem

These work as advertised: ``` grep -ir 'hello world' . grep -ir hello\ world . ``` These don't: ``` argumentString1="-ir 'hello world'" argumentString2="-ir hello\\ world" grep $argumentString1 . grep $argumentString2 . ``` Despite `'hello world'` being enclosed by quotes in the second example, grep interprets `'hello` (and `hello\`) as one argument and `world'` (and `world`) as another, which means that, in this case, `'hello` will be the search pattern and `world'` will be the search path. Again, this only happens when the arguments are expanded from the `argumentString` variables. grep properly interprets `'hello world'` (and `hello\ world`) as a single argument in the first example. Can anyone explain why this is? Is there a proper way to expand a string variable that will preserve the syntax of each character such that it is correctly interpreted by shell commands?

Original source

Related problems