14
> echo "hi"
hi
> VAR='echo "hi"'
> $VAR
"hi"

Why is the output of the above commands different?

A similar thing occurs with single quotes:

> VAR="echo 'hi'"
> $VAR
> 'hi'
Cory Klein
  • 18,911
  • 6
    Please do not get in the habit of embedding executable script snippets in variables. This tends to be tricky at best and eval is a minefield of potential security holes which you must tread very carefully – jw013 May 11 '12 at 17:15
  • @jw013 Good point and great articles. I like the quote "Variables hold data, functions hold code." from the first link, but for my usage, the data that is given to a function (in this case, at) is code. Any tips on a safer way to organize/collect code that will be given to at? – Cory Klein May 11 '12 at 17:38
  • at takes sh syntax as input. Thus generating input for at means generating valid, properly quoted sh syntax from arbitrary input, which is not trivial, so I'd try to avoid it if at all possible. It would really help if you could give a little more detail on what you are trying to accomplish. – jw013 May 11 '12 at 17:56
  • Sorry, I didn't want to distract with too much detail, but what I'm doing isn't really complicated, IMO. I'm creating a script that takes a "time" and a "message". It then runs at for the given "time", and tells at to run the command dzen2. dzen2 takes the "message" from stdin, and also uses some other static parameters. The difficulty is that I need to pipe the "message" parameter from the user into the dzen2 command, but I'm not actually running dzen2 myself, I'm telling at to do it. – Cory Klein May 11 '12 at 18:02
  • @jw013 I ended up getting everything to work just fine, by the way. – Cory Klein May 11 '12 at 18:33
  • "Variables hold data, functions hold code." Unless it's a lisp. – Joseph Kern May 12 '12 at 16:50
  • 1
    http://superuser.com/questions/360966/how-do-i-use-a-bash-variable-string-containing-quotes-in-a-command/936487#936487 || http://stackoverflow.com/questions/7454526/bash-variable-containing-multiple-args-with-quotes – Ciro Santilli OurBigBook.com Jul 05 '15 at 08:27

3 Answers3

18

The extra pair of quotes would be consumed only by an extra evaluation step. For example forced by eval:

bash-4.2$ VAR='echo "hi"'

bash-4.2$ $VAR
"hi"

bash-4.2$ eval $VAR
hi

But generally is a bad idea to put commands with parameters in one string. Use an array instead:

bash-4.2$ VAR=(echo "hi")

bash-4.2$ "${VAR[@]}"
hi
manatwork
  • 31,277
  • 1
    It's also important to note that quotes are evaluated differently; double quotes (") allow evaluation of the enclosed string, single quotes (') print the string as a literal. Example: "$(ls)" and '$(ls)'. This is the reason why quotes appear in original questions examples. – Joseph Kern May 12 '12 at 17:00
  • An array is also a source of problems. Code belongs to functions, data to variables. The example you present works only because the quotes are removed in the split of the array. A printf '<%s> ' "${VAR[@]}" will show that quotes have been removed already. If you set VAR as VAR=(echo \"hi\") to actually have quotes, the same problem appears again, $ ${VAR[@]} will print "hi" –  Jan 17 '16 at 06:10
10

Quote removal only occurs on the original input words, not on the result of expansions. Quotes that are part of expanded variables are untouched.

jw013
  • 51,212
3

If you step back a bit, you can see why variable substitution absolutely should retain quotes.

The point of quotes in a Unix/Linux/BSD shell is to keep pieces of a string together that would otherwise get parsed as multiple strings. Since by default a shell uses whitespace as a token separator, a string with spaces (like "one two three") if not quoted or escaped somehow, would get parsed as 3 strings: "one", "two" and "three".

If a programmer wants a string with the value of some variable interpolated:

VAR=two
STRING="one $VAR three"

the shell should absolutely not remove the quotes: the string containing spaces would get parsed as 3 smaller strings.