The Unix shells have not one, not two, but three different mechanisms for quoting whitespace or other special characters when there's a need to enter them in arguments on the command line, such as filenames. They are the double quote " , the single quote ' , and the backslash \ . These all have slightly different rules, but the distinctions can end up being quite useful, if you can remember them.

  • The backslash simply quotes the next character, whatever it is. (Okay, so that's not "slightly different" from the quote marks, it's completely different.)

    The find command's -exec option requires that the command to be executed be terminated by a semicolon, but the semicolon would be special to the shell, so must be quoted:

    	find . -name core -exec rm {} \;

    The expr command's multiplication operator is, naturally enough, an asterisk, but of course the asterisk is the shell's main glob character, so must be quoted:

    	expr 6 \* 9

  • Single quotes quote everything between them; there are no special characters between single quotes. This means, though, that you can't have a single quote in a single-quoted string; that single quote would be treated as the end of the string, and there's no way to suppress that meaning.

    Example: sed uses lots of metacharacters which are also special to the shell; you usually want to enclose a sed expression in single quotes:

    	sed 's/  *$//'

  • Where things get interesting is with double quotes. Between double quotes, the meaning of most special characters is removed, except the dollar sign, backslash, and backtick. This means that within double-quoted strings, environment variables are still expanded, command substitution between backticks is still performed, and backslashes can still be used to further suppress the interpretation of these remaining few -- that is, to get a double quote, dollar sign, backtick, or backslash withing a double-quoted string, you can quote any of them with a backslash.

    Example: while debugging a shell script, you might insert temporary echo statements to print out the values of environment variables:

    	echo "\$HOME = $HOME"

    would result in a line like

    	$HOME = /home/scs

These rules are pretty straightforward, but things start getting messy in situations where a string will be evaluated by the shell multiple times. If an argument contains special characters which must be quoted, and if the argument is a string (perhaps an embedded shell command) which will be interpreted again later, you have to quote all the quotes somehow. This can get real hard to think about real fast; sometimes you have little choice but to resort to the dread, unsatisfying technique of trial and error. If neither doubled nor quadrupled (i.e. doubled doubled) backslashes work, perhaps it's time for octupled backslashes... (perl's Camel book calls these "leaning toothpicks" or some such.)

For example, I have a command called filter which applies a filter to a number of files, replacing them with the filtered output. The usage is

	filter command file(s)

but the command must be a single argument, so it must usually be quoted. For example, I might invoke

	filter "sed 's/  *$//'" *

to remove trailing spaces from all lines from all files in the current directory.

In another script, I find the invocation

	echo "cat > $file <<\\%EOF%"

This is from a shell script that writes a shell script, and is supposed to generate a line like

	cat > filename <<\%EOF%

To discover the above example, I invoked

	grep \\\\\\\\ *

in my bin directory! I wanted to search for \\, but \ is special to grep and so must be quoted as \\\\ within grep, but \ is also special to the shell and so I needed to type 8 of them.

Log in or register to write something here or to contact authors.