Shell – Why is echo ignoring the quote characters

echoquotingshell

The echo command isn't including the complete text that I give it. For example, if I do:

   $ echo ' echo PARAM=`  grep  $ARG  /var/tmp/setfile  | awk '{print $2}' `    '

It outputs:

echo PARAM=`  grep  $ARG  /var/tmp/setfile  | awk {print } `

The single quotes (') I had in my echo command aren't included. If I switch to double quotes:

$ echo " echo PARAM=`  grep  $ARG  /var/tmp/setfile  | awk '{print $2}' `  "

echo doesn't output anything at all! Why is it leaving out the single quotes in the first example and outputting nothing in the second? How do I get it to output exactly what I typed?

Best Answer

Your shell is interpreting the quotes, both ' and ", before they even get to echo. I generally just put double quotes around my argument to echo even if they're unnecessary; for example:

$ echo "Hello world"
Hello world

So in your first example, if you want to include literal quote marks in your output, they either need to be escaped:

$ echo \'Hello world\'
'Hello world'

Or they need to be used within a quoted argument already (but it can't be the same kind of quote, or you'll need to escape it anyway):

$ echo "'Hello world'"
'Hello world'

$ echo '"Hello world"'
"Hello world"

In your second example, you're running a command substitution in the middle of the string:

grep  $ARG  /var/tmp/setfile  | awk {print $2}

Things that start with $ are also handled specially by the shell -- it treats them as variables and replaces them with their values. Since most likely neither of those variables are set in your shell, it actually just runs

grep /var/tmp/setfile | awk {print}

Since grep only sees one argument, it assumes that argument is the pattern you're searching for, and that the place it should read data from is stdin, so it blocks waiting for input. That's why your second command appears to just hang.

This won't happen if you single-quote the argument (which is why your first example nearly worked), so this is one way to get the output you want:

echo \'' echo PARAM=`  grep  $ARG  /var/tmp/setfile  | awk '{print $2}' `    '\'

You can also double-quote it, but then you'll need to escape the $s so the shell doesn't resolve them as variables, and the backticks so the shell doesn't run the command substitution right away:

echo "' echo PARAM=\`  grep  \$ARG  /var/tmp/setfile  | awk '{print \$2}' \`    '"
Related Question