|
Chapter 8 How the Shell Interprets What You Type
|
|
I can't understand why some people see Bourne shell quoting as a scary,
mysterious set of many rules.
Bourne shell quoting is simple.
(C shell quoting is slightly more complicated.
See article
8.15
.)
The overall idea is: quoting turns off (disables) the special meaning of
characters
.
There are three quoting characters: a single quote ('
),
a double quote ("
), and a backslash (\
).
Note that a backquote (`
) is not
a quoting character - it does
command substitution (9.16
)
.
Below are the characters that are special to the Bourne shell.
You've probably already used some of them.
Quoting these characters turns off their special meaning.
(Yes, the last three characters are quote marks.
You can quote quote marks; more on that later.)
# & * ? [ ] ( ) = | ^ ; < > ` $ " ' \
Space, tab, and newline also have special meaning: as argument separators.
A slash (/
) has special meaning to UNIX itself, but not the
shell - so quoting doesn't change the meaning of slashes.
Table 8.1
summarizes the rules; you might want to look back at it while you read the
examples.
Table 8.1: Bourne Shell Quoting Characters
Quoting Character |
Explanation |
'xxx
' |
Disable all special characters in xxx
.
|
"xxx
" |
Disable all special characters in xxx
except $
,
`
, and \
.
|
\x
|
Disable special meaning of character x
.
At end of line, a \
removes the newline
character (continues line).
|
To understand which characters will be quoted, imagine this:
the Bourne shell reads what you type at a prompt, or the lines in a shell
script, character by character from first to last.
(It's actually more complicated than that, but not for the purposes of quoting.)
When the shell reads one of the three quoting characters, it:
Strips away that quoting character.
Turns off (disables) special meaning of some or all other character(s) until the
end of the quoted section, by the rules in
Table 8.1
.
You also need to know how many characters will be quoted.
The next few sections have examples to demonstrate those rules.
Try typing the examples at a Bourne shell prompt, if you'd like.
(Don't use C shell;
it's different (8.15
)
.)
If you need to start a Bourne-type shell, type sh
; use CTRL-d
when you're done.
A backslash
(\
) turns off special meaning (if any)
of the next character.
For example, \*
is a literal asterisk, not a filename wildcard.
So, the first
expr
(45.28
)
command gets the three arguments
79 * 45
and multiplies those two numbers:
$ expr 79 \* 45
3555
$ expr 79 * 45
expr: syntax error
In the second example, without the backslash, the shell expanded *
into a list of filenames - which confused expr
.
(If you want to see what I mean, repeat those two examples using
echo
(8.6
)
instead of expr
.)
A single quote
('
) turns off special meaning of all
characters until the next single quote is found.
So, in the command line below, the words between the two
single quotes are quoted.
The quotes themselves are removed by the shell.
Although this mess is probably not what you want, it's a good
demonstration of what quoting does:
$ echo Hey! What's next? Mike's #1 friend has $$.
Hey! Whats next? Mikes
Let's take a close look at what happened.
Spaces outside the quotes are treated as argument separators; the shell
ignores the multiple spaces.
As article
8.6
explains, echo
prints a single space between each argument it gets.
Spaces inside the quotes are passed on to echo
literally.
The question mark (?
) is quoted; it's given to echo
as is,
not used as a wildcard.
So, echo
printed its first argument Hey!
and a single space.
The second argument to echo
is Whats next? Mikes
;
it's all a single argument because the single quotes surrounded the spaces
(notice that echo
prints the two spaces after the question mark:
?
).
The next argument, #1
, starts with a hash mark, which is a
comment character (44.2
)
.
That means the shell will ignore the rest of the string; it isn't passed
to echo
.
Double quotes
("
) work almost like single quotes.
The difference is that double quoting allows the characters $
(dollar sign), `
(backquote), and \
(backslash)
to keep their special meanings.
That lets you do
variable substitution (6.8
, 6.1
)
and
command substitution (9.16
)
inside double quotes - and also to stop that substitution where you need to.
For now, let's repeat the example above.
This time, put double quotes around the single quotes (actually, around
the whole string):
$ echo "Hey! What's next? Mike's #1 friend has $$."
Hey! What's next? Mike's #1 friend has 18437.
The opening double quote isn't matched until the end of the string.
So, all the spaces between the double quotes lose their special meaning - and the
shell passes the whole string to echo
as one argument.
The single quotes also lose their special meaning - because double quotes
turn off the special meaning of single quotes!
So, the single quotes aren't stripped off as they were in the previous
example; echo
prints them.
What else lost its special meaning?
The hash mark (#
) did; notice that the rest of the string was
passed to echo
this time - because it wasn't "commented out."
But the dollar sign ($
) didn't lose its meaning;
the $$
was expanded
into the shell's
process ID number (38.3
)
(in this shell, 18437
).
In the previous example, what would happen if you put the $
inside
the single quotes?
(Single quotes turn off the meaning of $
, remember.)
Would the shell still expand $$
to its value?
Yes, it would: the single quotes have lost their special meaning,
so they don't affect any characters between themselves:
$ echo "What's next? How many $$ did Mike's friend bring?"
What's next? How many 18437 did Mike's friend bring?
How can you make both the $$
and the single quotes print literally?
The easiest way is with a backslash, which still works inside double
quotes:
$ echo "What's next? How many \$\$ did Mike's friend bring?"
What's next? How many $$ did Mike's friend bring?
Here's another way to solve the problem.
A careful look at this will show a lot about shell quoting:
$ echo "What's next? How many "'$$'" did Mike's friend bring?"
What's next? How many $$ did Mike's friend bring?
To read that example, remember that a double quote quotes characters
until the next double quote is found.
The same is true for single quotes.
So, the string What's next? How many
(including the space at the end) is inside a pair of double quotes.
The $$
is inside a pair of single quotes.
The rest of the line is inside another pair of double quotes.
Both of the double-quoted strings contain a single quote; the double
quotes turn off its special meaning and the single quote is printed literally.
You can't put single quotes inside single quotes.
A single quote turns off all
special meaning until the next
single quote.
Use double quotes and backslashes.
Once you type a single quote or double quote, everything is quoted.
The quoting can stretch across many lines.
(The C shell doesn't work this way.)
For example, in the short script shown in
Figure 8.1
,
you might think that the $1
is
inside quotes... but it isn't.
Actually, everything but
$1
is in quotes.
The gray shaded area shows the quoted parts.
So $1
is expanded by the Bourne shell, and not by awk
.
Here's another example.
Let's store a
shell variable (6.8
)
with a multiline message, the kind that might be used in a shell program.
A shell variable must be stored as a single argument; any argument
separators (spaces, etc.) must be quoted.
Inside double quotes, $
and `
are interpreted
(before
the variable is stored, by the way).
The opening double quote isn't closed by the end of the first line;
the Bourne shell prints
secondary prompts (9.13
)
(>
) until all quotes
are closed:
$ greeting="Hi, $USER.
> The date and time now
> are: `date`."
$ echo "$greeting"
Hi, jerry.
The date and time now
are: Tue Sep 1 13:48:12 EDT 1992.
$ echo $greeting
Hi, jerry. The date and time now are: Tue Sep 1 13:48:12 EDT 1992.
$
The first echo
command line uses double quotes.
So, the shell variable is expanded,
but the shell doesn't use the spaces and newlines in the variable
as argument separators.
(Look at the extra spaces after the word are:
.)
The second echo
doesn't use double quotes.
The spaces and newlines are treated as argument separators; the shell
passes 14 arguments to echo
, which prints them with single
spaces between.
A backslash has a quirk you should know about.
If you use it outside quotes, at the end of a line (just before the
newline), the newline will be deleted
.
Inside single quotes, though, a backslash at the end of a line is
copied
as is.
Here are examples.
I've numbered the prompts (1$
, 2$
, and so on):
1$ echo "a long long long long long long
> line or two"
a long long long long long long
line or two
2$ echo a long long long long long long\
> line
a long long long long long longline
3$ echo a long long long long long long \
> line
a long long long long long long line
4$ echo "a long long long long long long\
> line"
a long long long long long longline
5$ echo 'a long long long long long long\
> line'
a long long long long long long\
line
You've seen an example like example 1
before.
The newline is in quotes, so it isn't an argument separator;
echo
prints it with the rest of the (single two-line) argument.
In example 2
, the backslash before the newline tells the shell to delete
the newline; the words long
and line
are passed to
echo
as one argument.
Example 3
is usually what you want when you're typing long lists of
command-line arguments: Type a space (an argument separator) before the
backslash and newline.
In example 4
, the backslash inside the double quotes is ignored
(compare to example 1).
Inside single quotes, as in example 5
, the backslash has no
special meaning; it's passed on to echo
.
|