[comp.unix.shell] Csh, alias substitution, & backslash

chris@mimsy.umd.edu (Chris Torek) (11/14/90)

(this almost certainly belongs in comp.unix.shell, so I have redirected
followups there, not that I actually expect any)

In article <6663@ge-dab.ge.com> brooks@ge-dab.ge.com (Stephen Brooks) writes:
>  In the C-shell, you can prevent alias substitution by preceding the
>aliased command with a backslash. ... why does "\rm" work, but "\cd"
>does not?  Yes, I realize that "cd" is a C-shell builtin command, but
>I haven't been able to find any discussion on how the \ prevents alias
>substitution.

It is a side effect.

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 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] 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:
 a) strips the 8th bit of each byte of each word
 b) 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.)
-- 
In-Real-Life: Chris Torek, Univ of MD Comp Sci Dept (+1 301 405 2750)
Domain:	chris@cs.umd.edu	Path:	uunet!mimsy!chris