## 27.10. Which One Will the C Shell Use?

[Section 27.9 shows how to control whether bash uses a built-in command, a shell function, or an external command. The way you do that in the C shell is a little, errr, different. Chris Torek explains why, for example, `\rm` disables an alias for rm and `\cd` disables the built-in cd command. He starts with a fairly complex explanation, then gives some practical guidelines. At the end is a "review" that's easy to follow and fun too. -- JP]

The C shell first breaks each input line into a word vector. It then matches against aliases. Since `\rm` does not match `rm`, any alias is ignored. Eventually the C shell fully applies any quoting (since an alias can include quotes, some of this work must be deferred; since an alias can include multiple words, more word vector work must be done as well; it all gets rather hairy).

The C shell implements quoting by setting the eighth bit (bit 7) of each byte of a quoted character. Since `'*'|0x80` [a character ORed with 80 hex, a.k.a. 10000000 binary -- JP] is not the same character as `'*'`, this prevents filename expansion, further word breaking, and so on.

Eventually, the shell has a fully "parsed" line. It then compares `word[0]` [the first word on the command line -- JP] against all the built-ins. If there is a match, it runs the corresponding built-in command (and it is up to that command to expand any remaining words; for instance, `ls *` in a directory containing only the file -l produces a long listing, but `jobs *` produces a usage message). If not, the shell performs globbing on the current word list, producing a new word list, and then:

1. Strips the eighth bit of each byte of each word

2. exec( )s the resulting command.

This means that `\cd` not only bypasses any alias, but also reaches the built-in scanner as:

>     'c'|0x80, 'd', '\0'

which does not match the built-in command:

>     'c', 'd', '\0'

and so does not run the cd builtin. It is later stripped, and the shell looks for an external program called cd.

If you want to avoid alias substitution but not built-in matching, you can replace:

>     \cd foo    or   \rm foo

with:

>     ''cd foo   or   ""rm foo

These do not match the aliases -- during alias scanning they have quote pairs in front of them -- but they do match any builtin because the quotes have by then been stripped (setting bit 7 of all the characters contained between the two quotes, here none).

Incidentally, since alias expansion occurs early, you can do some peculiar things with it:

>     % [
>     Missing ].             . . . on some systems, there is a command named [, sometimes standalone,
>                            and sometimes symlinked to test.
>     % alias [ echo foo
>     % [
>     foo                              . . . alias expansion occurs before globbing

>     % unalias [
>     unalias: Missing ].              . . . unalias globs its arguments!

>     % unalias \[
>     % alias unalias echo foo
>     unalias: Too dangerous to alias that.              . . . the C shell attempts caution...

>     % alias \unalias echo foo
>     % alias
>     unalias   (echo foo)
>     % unalias unalias
>     foo unalias                      . . . but fails!

>     % ''unalias unalias
>     % alias
>     %                                . . . Fortunately, there is an exit.

> NOTE: On some systems, there is a command named [, sometimes standalone, and sometimes symlinked to test.

-- CT

Copyright © 2003 O'Reilly & Associates. All rights reserved.