[Chapter 8] 8.12 Which One Will the C Shell Use?
Author: Jerry Peek, Tim O'Reilly & Mike Loukides
Date: 1998-08-04T21:34:26Z

#

| Chapter 8 How the Shell Interprets What You Type |

## 8.12 Which One Will the C Shell Use?

[Article 8.11 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 8th 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 file name 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 [filename wildcard expansion-JP ] on the current word list, producing a new word list, and then:

1. strips the 8th 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 do match any builtin since 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 ].
>     % 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.)

- CT on Usenet, 14 November 1990

8.11 Which One Will bash Use? |  | 8.13 Is It "2>&1 file" or "> file 2>&1"? Why?