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

brooks@ge-dab.ge.com (Stephen Brooks) (11/12/90)

  In the C-shell, you can prevent alias substitution by preceding the
aliased command with a backslash.  For example, you might have:

        % alias rm
        rm -i
        % alias cd
        cd !* ; pwd

However, 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.  For example (using
the above aliases):

==================== this does what I expect ==================== 

        % ls
        file1           file2           file3
        % rm *
        rm: remove file1? n
        rm: remove file1? n
        rm: remove file1? n
        % ls
        file1           file2           file3
        % \rm *
        % ls
        %

==================== this does not do what I expect ==================== 

        % cd
        /usr/users/steve
        % \cd
        cd: Command not found.

So, why does the \ prevent the C-shell from recognizing the builtin
command as well as preventing alias substitution?  Feature?  Bug?
--
%% Stephen (Steve) M. Brooks       %% brooks@ge-dab.ge.com              %%
%% GE Simulation & Control Systems %% ...!uunet!ge-dab.ge.com!brooks    %%
%% P.O. Box 2825, Rm. 1370         %% ...!uunet!sunny.dab.ge.com!brooks %%
%% Daytona Beach, FL  32115-2825   %% voice: (904) 239-4855             %%

maart@cs.vu.nl (Maarten Litmaath) (11/14/90)

In article <6663@ge-dab.ge.com>,
	brooks@ge-dab.ge.com (Stephen Brooks) writes:
)...
)        % alias rm
)        rm -i
)        % alias cd
)        cd !* ; pwd
)
)However, why does "\rm" work, but "\cd" does not?  [...]

Feature.  An initial backslash prevents both alias substitution and
builtin interpretation.  If you want to skip aliases only, use this:

	% ''cd
or
	% ""cd
--
nreadwin@micrognosis.co.uk (Neil Readwin) on "snuff" films:
"Seen one ? I was *in* one. They tortured me horribly and then killed me
 with a single shot in the back of the head ! Following total brain death
 I gave up acting and became a VMS hacker."

arthur@sgi.com (Arthur Evans) (11/14/90)

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.  For example, you might have:
>
>        % alias rm
>        rm -i
>        % alias cd
>        cd !* ; pwd
>
>However, 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.  

Well, here's my shot in the dark.  The csh is setting the high
bit on the first character of your command to "quote" it--prevent
it from matching a metacharacter when the shell does filename
substitution.  So your command, with high bit set, is searched
for in the list of builtin commands.  When the shell doesn't 
find it there it does filename substitution--"globbing"--in the
course of which it strips the high bit.  Then it searches for
your command, sans high bit, in the hash list and/or search path.
In the case of "rm," the shell finds what it's looking for.  In 
the case of "cd," it doesn't.

OK
-arthur

--
"If I had all the money I'd spent on drink ... I'd spend it on drink."
					-- Sir Henry Rawlinson

Arthur Evans 					arthur@rawlinson.wpd.sgi.com

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