Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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

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?

like image 306
Ben Wilhelm Avatar asked Aug 27 '12 06:08

Ben Wilhelm


People also ask

How do you keep quotes in a bash argument?

When you want to pass all the arguments to another script, or function, use "$@" (without escaping your quotes). See this answer: Difference between single and double quotes in Bash.

How do you pass a double quote into a string in a shell script?

To quote a generic string with double quotes, perform the following actions: Add leading and trailing double quotes: aaa ==> "aaa" Escape with a backslash every double quote character and every backslash character: " ==> \", \ ==> \\

Why is it a good practice to put arguments in quotes when assigning them to variables?

In short, quote everything where you do not require the shell to perform word splitting and wildcard expansion. Single quotes protect the text between them verbatim. It is the proper tool when you need to ensure that the shell does not touch the string at all.

What is the difference between single quotes and double quotes for shell?

Double quotes are similar to single quotes except that it allows the shell to interpret dollar sign ($), backtick(`), backslash(\) and exclamation mark(!). The characters have special meaning when used with double quotes, and before display, they are evaluated.


1 Answers

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.

like image 106
Jonathan Leffler Avatar answered Oct 22 '22 06:10

Jonathan Leffler