If your shell always get’s you wrong - quote the right way

posts/quoting/title.jpg

Here is another question that often comes up by my students and clients:

” … how can I solve the problem with these special-characters? The shell always gets me wrong …”

The fast and simple answer to this is: You have to quote!

… and you have to to it the right way.

But let’s start from the beginning:

As you know, there are characters at the command line, that simply has special meanings for the shell.

You use them for instance, for referencing the content of a variable (“$”)

robert@demo:~$ echo Hello $NAME

… or for redirecting a datatream to a file (“>”):

robert@demo:~$ ls -l /etc > $TEMPFILE

But everytime you wanna use these special characters without their special meaning for the shell, you have to take special care about it.

(huh - three times “special” in one sentence. this must be really special ;-) )

So instead of writing

robert@demo:~$ echo Buy this book for $9 now
Buy this book for now

you have to write something like

robert@demo:~$ echo 'Buy this book for $9 now'
Buy this book for $9 now

In this way, the shell won’t try to interprete $9 as a variable. Instead it would take the “$”-sign just like what it is: a $-sign.

This mechanism is called “quoting” and technically explained for instance in depth in the Bash-Documentation.

Let me show you, how the quoting works. And your shell never gets you wrong again … ;-)

What special-characters you should care about

Special characters that need special handling in the shell are obviously the following:

<space> ; , & | > <.

But also the lesser known meta-characters ( and ) and the placeholders for the filename globbing ( * ? [ ] ) need special handling when used at the command-line.

If you use history expansion (why would you not?), then the character ! has also to be included in the “TakeSpecialCare”-list.

And because the backslash (\) is used for quoting, you have to quote it if you like to use it as really only a backslash.

The same goes for the " and the ' characters. You often use them if you quote intuitively, but they need special care if you want to use them as the characters they are.

So, the following characters need special care when used in the shell:*

& ; ( ) < > space tab * ? [ ] ! “ ‘ ` # -

*Note: Why the dash ‘-‘?

Typically a dash (‘-‘) doesn’t have a special meaning for the shell. But for commands started from the commandline it sometimes has - espacially if it is the first character of a parameter. Think about for instance ls -l, where “-l” is be the name of a file …

toolbox If you wanna know more about such tools like the once I talk about here, and especially if you write shell-scripts or plan to write shell-scripts:

Get My Free Ebook “The Shellscripters Toolbox“

In this PDF I show you a load of useful commandline-tools. Tools you can use especially for shellscripting, but also perfectly for your day-to-day work at the commandline.

How to do this special handling

Generally, you have three options to let the shell ignore characters with special meanings:

  • single-character-quoting: Prepend the special character with a backslash \

    echo By this book for \$9 only

  • “weak-quoting”: Surround the string containing one or more special characters by "

    echo "This is an ampersand: &"

  • “hard-quoting”: Surround the string containing one or more special characters by '

    echo 'By this book for $9 only'

Perhaps you’ve heard about all or some of these quoting-options.

But what are the differences?

Use \ to quote only one single character

Obviously, the first variant is only usefull for single characters.

Use this method, if you only want to quote a single known character or you want to quote the “quote-markers” (\, " and ').

Hint: What happens, if the shell sees the quote-markers (\, " or ') on your command-line?

It thinks “oh ok - let’s ignore those following special characters” and … removes the quote-markers itself before interpreting the commandline further.

Here are some examples:

spaces in filenames:

~$ mkdir my\ pictures	# --> creates a directory named "my pictures"

Instead of creating the two directories “my” and “pictures” (as it would without the backslash before the space), mkdir creates only one with a space inside the name (“my pictures”).

do not expand variables:

~$ echo hello $USER
hello robert
~$ echo hello \$USER
hello $USER

output the “quote-helpers”:

~$ echo try to use "string" or \n for quoting
try to use string or n for quoting
~$ echo try to use \"string\" or \\n for quoting
try to use "string" or \n for quoting

output a single asterisk (*):

if the shell “sees” an asterisk at the commandline, it tries to interpret the resulting string as a search-pattern for filenames.

If there are files that correspond to the pattern, then the shell substitutes the pattern by a list of that files. If no files where found, the shell ignores the pattern and leaves the pattern alone.

~$ echo *.txt
list.txt error.txt	<-- list with filenames matching the pattern
~$ echo *.text
*.text            <-- no filename matches the pattern, no substitution
~$ echo \*.txt
*.txt

“Weak-quoting” with double quotes “ … “

The second variant - often called “weak-quoting” - is the way you usually quote intuitively.

You use a filename containing spaces?

… surround it with double-quotes!

~$ cp financial report.doc /tmp
cp: cannot stat ‘financial’: No such file or directory
cp: cannot stat ‘report.doc’: No such file or directory
~$ cp "financial report.doc" /tmp

sure - you could quote the single space with a backslash, but surrounding the whole string with double-qoutes is more easy to read I think.

You want to print out a string with a sequence of spaces?

… surround the whole thing with double-quotes!

~$ echo hello        world
hello world
~$ echo "hello        world"
hello         world
  • at the first try: the shell takes the sequence of spaces between “hello” and “world” as only one separator at the commandline and the echo-command gets two parameters for output: “hello” and “world”

  • at the second try: we give the echo-command only one parameter for output containing all the important spaces.

… ok Robert - I’ve got it. But why the hell is this called weak-quoting?

Glad you ask ;-)

Why it is called “weak-qouting”

Well - it’s called “weak-quoting”, because there are characters, which are nevertheless interpreted by the shell.

Imagine, you want to output a string (with lot’s of spaces) and replace a variable-name by it’s content:

~$ echo "hello          $NAME"
hello          Robert

That’s great: The shell preserves the spaces and at the same time interprets the “$”-sign and expands the variable.

Between double-quotes, the following special characters will be interpreted: $, \, ! and the “backticks” (`).

Especially the backslash is handy if you want to quote something within your weak-quoted string:

~$ echo "I know you are $NAME, because of \$NAME"
I know you are Robert, because of $NAME

“Hard-quoting” with single quotes ‘ … ‘

But what if you want nothing to be interpreted by the shell? The strings shall be used as they are? Use the hard-quoting with single quotes:

~$ echo 'Hi $NAME, eat this: "; <> |"'
Hi $NAME, eat this: "; <> |"

That’s it

As you could see, you can use nearly any special character in any combinations in the shell without the fear of being misunderstood.

I hope you enjoyed this lesson. See you next time

Robert

toolbox If you wanna know more about such tools like the once I talk about here, and especially if you write shell-scripts or plan to write shell-scripts:

Get My Free Ebook “The Shellscripters Toolbox“

In this PDF I show you a load of useful commandline-tools. Tools you can use especially for shellscripting, but also perfectly for your day-to-day work at the commandline.