Tuesday, November 07, 2006

bash Quoting

I thought I'd compile a list for bash's quoting rules for my own easy reference. I guess it might help others as well. Here goes then..

Escape Character (\)

Backslash (\) is used to remove the special meaning of the following character.
For example, \$ prints a $ instead of it being interpreted to signify a parameter.

An exception to the above statement is \. In the case of this sequence, bash looks for line continuation. Essentially, the character is removed completely.

Single Quotes ('')

Single quotes ('') are strong quotes. They bypass all the expansions. Everything inside single quotes is untouched.

You cannot have single quotes inside single quotes. Not even when backslash escaped. Use '\'' instead.

Double Quotes ("")

Double quotes allow parameter expansion, command substitution and arithmetic exansion. In short, all the expansions associated with $.

` is the archaic way of command substitution and is allowed inside double quotes.

\ inside double quotes is allowed only when used for \, `, $ and . In short, all the special characters which retain their special meaning inside double quotes.

Double quotes inside double quotes are allowed with used with a \. That is, \"

If history expansion is enabled, it'll be performed when ! is encountered inside double quotes. This can be bypassed with \!. The backslash preceding the ! is NOT removed.

Note: This can be annoying in your interactive shell when you get an error about history expansion when doing something like echo "Hello world!". The way to bypass this is to do "Hello world"\! or 'Hello world!' or Hello world\!

Examples:

Expression Value

$testvar hello
\$testvar $testvar
'$testvar' $testvar
"$testvar" hello
"'$testvar'" 'hello'
""$testvar"" hello
"\"$testvar\"" "hello"
~mrugesh /home/mrugesh
"~mrugesh" ~mrugesh
'~mrugesh' ~mrugesh

$' and $"

$'string' expands the string and the backslash escaped characters are replaced by the ANSI C standards. The expanded result is equivalent to being single quoted, as if $ is not present. Here are the characters expanded:

\a alert (bell)
\b backspace
\e an escape character
\f form feed
\n new line
\r carriage return
\t horizontal tab
\v vertical tab
\\ backslash
\' single quote
\nnn the eight-bit character whose value is the octal value nnn (one to three digits)
\xHH the eight-bit character whose value is the hexadecimal value HH (one or two hex digits)
\cx a control-x character

As an example:
$ echo -e 'Hello\nworld'
Hello
world

$ echo $'Hello\nworld'
Hello
world

$" translates the quoted string according to the current locale. For C and POSIX locales, the $ sign is ignored. If translated and replaced, the replacement is double quoted.

$* and $@

These two special variables are used in terms of positional parameters. They produce the same output when unquoted. When double quoted however, "$*" produces one word with all the positional parameters separated by the first IFS character; while "$@" produces different words, separated by spaces.

To elaborate, if "$*" is fed as an argument to a command, it is just one single argument ($# will show you 1). If "$@" is fed as an argument, it is several different arguments($# will show you N, where N equals the number of positional parameters provided.).

Most times, you'd want to use "$@".

When unquoted, the output of both is grounds for word splitting.

For example,

$ set -- "first argument" "second argument" "third argument"

$ for i in "$@"; do echo ">${i}<"; done
>first argument<
>second argument<
>third argument<

$ for i in "$*"; do echo ">${i}<"; done
>first argument second argument third argument<

$ for i in $@; do echo ">${i}<"; done
>first<
>argument<
>second<
>argument<
>third<
>argument<

$ for i in $*; do echo ">${i}<"; done
>first<
>argument<
>second<
>argument<
>third<
>argument<

This post is for a quick reference. Look here for a proper explanation: http://www.grymoire.com/Unix/Quote.html. This document is not restricted to just bash.

4 comments:

Anonymous said...

I knew there was a reason I liked Perl.

Mrugesh Karnik said...

LOL. Now am I to wait till someone comments about how good Python is?

Well, I guess this is knowledge worth having, since most of the Linux users I know spend most of their time on bash anyway. Even that's irrelevant, because I spend all of my time on bash..

Thrivikraman said...

Dude

[quote Not even when backslash escaped. Use '\'' instead. [/quote]

This is a bit confusing; the first sentence states that not even when back slash escaped, but the next sentence shows back slash escape.

Correct me if I have misunderstood :)

Mrugesh Karnik said...

Try this:

$ echo 'Mrugesh's blog'

What happens? The shell gives you the secondary prompt ( > being the default $PS2) because it thinks that the quoting isn't complete. This is because the starting ' and the ' before s match, the ' at the end however is unmatched.

$ echo 'Mrugesh\'s blog'

Again, the secondary prompt. The exact same thing again. Even the \ is ignored by the shell.

Now try this:

$ echo 'Mrugesh'\''s blog'

Works. What's happening here?

The opening ' is matched by the ' after Mrugesh. The \ then escapes the first of the following two ' from the shell. The next ', the one before s is then again matched by the ' at the end.

Indeed, this could have been written as:

$ echo Mrugesh\'s blog

Produces the same result.

Hopefully the confusion has been cleared. :)