[comp.unix.questions] which/type & built-ins

ok@quintus.UUCP (Richard A. O'Keefe) (01/01/90)

Does anyone know why the C shell command "which" (ok, /usr/ucb/which)
and the Bourne shell command "type" don't understand built-in commands?

The manual page for csh says
     which [ filename ] ...
	  which takes a list of names and looks for the files which
	  would be executed had these names been given as commands.
(Should be    ^^^ "would have been", such grammar!)
which makes it clear that "which if" isn't supposed to recognise "if"
as a command.  I don't quite see why; surely it would be easy for
/usr/ucb/which to execute an appropriate switch() after everything
else has failed.

The manual page for sh says
     type [ name ... ]
	  For each name, indicate how it would be interpreted if
	  used as a command name.
This certainly looks to me as though "type if" SHOULD succeed, and
"type type" _does_.  So why does "type while" say "while not found"
rather than "while is a shell builtin"?

reschly@BRL.MIL (Robert J. Reschly Jr.) (01/02/90)

      Richard,
You say:
> Does anyone know why the C shell command "which" (ok, /usr/ucb/which)
> and the Bourne shell command "type" don't understand built-in commands?

   The "which" command is an independent program (actually a C-shell
script) which can be called from any command interpreter.  Since the
various command interpreters offer differing sets of built-in commands,
"which" cannot presume to know anything about built-in commands.
Additionally there is no reasonable way for "which" to learn this
information.

> I don't quite see why; surely it would be easy for /usr/ucb/which to
> execute an appropriate switch() after everything else has failed.

   Resulting in "which blurfle" responding with "blurfle is a shell
built-in"?  What action would you have the switch() branch take?  Note
that another failure mode for "which" involves using a shell other than
/bin/csh while having a .cshrc in your home directory.  If this .cshrc
defines any aliases, "which" will gladly report them even though they are
probably inappropriate.

   As for "type", I have no good answers.  Given that "type type"
reports itself as a shell built-in it should be able to report on other
built-ins. My current shell of choice, "tcsh" handles this operation
correctly.

				Later,
				    Bob 
   --------
Internet: reschly@BRL.MIL (or BRL.ARMY.MIL)  Phone: (301)278-6808  AV: 298
UUCP:     ...!{{cmcl2,nlm-mcs,husc6}!adm,smoke}!reschly
Postal:   Robert J. Reschly Jr.
          U.S. Army Ballistic Research Laboratory
          Systems Engineering and Concepts Analysis Division
          Networking and Systems Development Team
          ATTN: SLCBR-SE-A  (Reschly)
          APG, MD  21005-5066             (Hey, *I* don't make 'em up!)

****  For a good time, call: (303) 499-7111.   Seriously!  ****

tale@cs.rpi.edu (David C Lawrence) (01/02/90)

In article <21912@adm.BRL.MIL> reschly@BRL.MIL (Robert J. Reschly Jr.) writes:
> Note that another failure mode for "which" involves using a shell
> other than /bin/csh while having a .cshrc in your home directory.

Not the only other failure mode, besides built-ins; it blows aliases
too, even when you are using csh.  Here's an article I wrote for a
local group on this topic a month ago:

================
Newsgroups: rpi.suns
Subject: Re: unaliasing
Date: 30 Nov 89 08:31:54 GMT

[Last update: Mon Jan  1 19:35:45 1990]
[ This was written in reply to a reply of someone who asked this:

   I want to know the full path name of a command. The "which" command reads
   ~/.cshrc to check for alias, but I want the unaliased form of the command.
   Is there a way to do this without modifying the ~/.cshrc file?

 It was not an attempt to answer that question, but rather the one
 in the follow-up that wanted to know how come which screwed up so much.]

Script started on Thu Nov 30 03:13:40 1989
bash$ which csh
/bin/csh
bash$ alias csh='echo foo'
bash$ which csh
/bin/csh
bash$ alias
alias csh="echo foo"
bash$ csh
foo
bash$ type csh
csh is aliased to `echo foo'.
bash$ /bin/csh
csh% which csh
/bin/csh
csh% alias csh 'echo foo'
csh% which csh
/bin/csh
csh% csh
foo
csh% which statement
no statement in /staff/cs/tale/bin /usr/local/gnu/bin /usr/bin/X11 /usr/local/bin /usr/etc /usr/bin /usr/ucb /bin /usr/5bin .
csh% cat > .cshrc
alias csh 'echo bar'
alias alias statement 'which is stupid about a lot of things ...'
csh% which statement
statement: 	 aliased to which is stupid about a lot of things ...
csh% which csh
csh: 	 aliased to echo bar
csh% csh
foo
csh% exit
csh% bash$ exit

script done on Thu Nov 30 03:16:06 1989

As has been pointed out, /usr/ucb/which reads your .cshrc to find out
some information, usually aliases.  It can get PATH from your
environment; I haven't bothered checking which gets precedence if path
information is in .cshrc.  It was very much written for csh, even
though it doesn't even work with it correctly.  The problem is that
which is a non-csh builtin attempting to get internal information from
the programme.  When using csh, the primary screw-ups are when you
either have a) an alias defined interactively which does not exist in
.cshrc or b) an alias mentioned in .cshrc which does not really exist in
your current shell, as in the examples above.

It does work correctly, however, for most csh users' normal
environments.  The "right way" is to have the function in the
shell.  Witness BASH's "type" builtin which gets it right for the
cases where csh fails.
================

Dave

[By the way, Robert, you might want to cut the length of your
.signature by 60%+ to avoid some flames.]
-- 
   (setq mail '("tale@cs.rpi.edu" "tale@ai.mit.edu" "tale@rpitsmts.bitnet"))

ok@quintus.UUCP (Richard A. O'Keefe) (01/02/90)

In article <21912@adm.BRL.MIL> reschly@BRL.MIL (Robert J. Reschly Jr.) writes:
>(I wrote):
>> Does anyone know why the C shell command "which" (ok, /usr/ucb/which)
>> and the Bourne shell command "type" don't understand built-in commands?

>   The "which" command is an independent program (actually a C-shell
>script) which can be called from any command interpreter.  Since the
>various command interpreters offer differing sets of built-in commands,
>"which" cannot presume to know anything about built-in commands.

I'm afraid this reason is bogus.  "which" expressly *DOES* recognise
***C*** shell aliases.  It goes so far as to read your ~/.cshrc file
just so that it can do this.  For this reason it isn't any _use_ in
anything other than the C shell.  For example,
	% which cd
	cd:	aliased to set old=$cwd; chdir !*; set-title-bar
	% sh -c "type cd"
	cd is a shell builtin
What is more, "which" may not even use the same $PATH as the shell:
	% sh
	$ PATH=/usr/ucb:/bin:/usr/bin:/usr/local/bin
	$ type unde
	unde not found
	$ which unde
	/hughes/ok/commands.d/unde

I think this clearly shows that any Bourne shell script which relies on
'which' is likely to get into serious trouble sooner or later.  Given
that it only makes sense to use 'which' from the C shell, where is the
harm in having 'which' recognise C shell commands as well as C shell aliases?

chet@cwns1.CWRU.EDU (Chet Ramey) (01/03/90)

In article <1297@quintus.UUCP> ok@quintus.UUCP (Richard A. O'Keefe) writes:

>The manual page for sh says
>     type [ name ... ]
>	  For each name, indicate how it would be interpreted if
>	  used as a command name.
>This certainly looks to me as though "type if" SHOULD succeed, and
>"type type" _does_.  So why does "type while" say "while not found"
>rather than "while is a shell builtin"?

Because `while' is a sh language construct (a statement), not a shell
builtin.  It's a small but important distinction, and one of the chief
reasons that programming in sh is so much better than programming in csh
(in csh, these constructs *are* implemented as builtins, using very ad-hoc
parsing with thousands of special cases that serves to reduce their
usefulness to almost zero). 




-- 
Chet Ramey
Network Services Group				"Help! Help! I'm being
Case Western Reserve University			 repressed!"
chet@ins.CWRU.Edu			

dce@smsc.sony.com (David Elliott) (01/03/90)

In article <21912@adm.BRL.MIL> reschly@BRL.MIL (Robert J. Reschly Jr.) writes:
>   The "which" command is an independent program (actually a C-shell
>script) which can be called from any command interpreter.  Since the
>various command interpreters offer differing sets of built-in commands,
>"which" cannot presume to know anything about built-in commands.
>Additionally there is no reasonable way for "which" to learn this
>information.

Good try, but I don't think I can buy that, at least not as the only
reason.

You see, "which" will also look for aliases if you have a ~/.cshrc.
If it was completely independent, it would at least look at SHELL
to see if you are running sh or csh as your default shell, and with
that info it could decide on a list of builtins to use.

IMHO, the best way would be for each shell to have a builtin
"what would I run if I gave this name" command, and Unix would
have a "what's the pathname of this command" command, like the
Tektronix systems have.

-- 
David Elliott
dce@smsc.sony.com | ...!{uunet,mips}!sonyusa!dce
(408)944-4073
"But Pee Wee... I don't wanna be the baby!"

ok@quintus.UUCP (Richard A. O'Keefe) (01/03/90)

In article <1990Jan2.160927.11935@usenet.ins.cwru.edu> chet@po.CWRU.Edu writes:
>In article <1297@quintus.UUCP> ok@quintus.UUCP (Richard A. O'Keefe) writes:
>>...[in Bourne shell]...  So why does "type while" say "while not found"
>>rather than "while is a shell builtin"?

>Because `while' is a sh language construct (a statement), not a shell
>builtin.

Yes, I *KNOW* that.  That's an excellent argument for having "type while"
say "while is a keyword" rather than "while is a shell builtin".
It is *NOT* an argument for having "type while" say "while not found".
Given the wording of the manual page, and a few seconds thought about
what would be useful, it seems most natural to interpret the response
"XXX not found" as meaning "a command cannot currently begin with the
word XXX, so you can use XXX as the name of a new command without
interfering with anything".

That is, in fact, what I wanted to use 'type' and 'which' for.
I often make up little shell scripts, and I get so tired of calling
them all 'zabbo' and then forgetting what they do.  I would like to
put together a command "howabout X" which tells me if X is "free" in
both the Bourne shell and the C shell, and the obvious way to do that
is to check the output of both 'which $X' and 'sh -c "type $X"'.  It
looks as though the best I can do is to do that and then filter out
keywords myself, which means that I have to adapt "howabout" myself
for every UNIX system I deal with...

Recommendation:
    it would be a Good Thing if "which X" said
	#Cshell builtin X	# when X is a C-shell built-in command
	#Cshell keyword X	# when X is part of a C-shell control structure
    and "type X" said
	X is a keyword		# when X is part of a control structure
    so that
	no X in $PATH		# which
	X not found		# type
    would mean that X was not currently in use as the first word of a
    possible command.

randy@chinet.chi.il.us (Randy Suess) (01/04/90)

In article <1301@quintus.UUCP> ok@quintus.UUCP (Richard A. O'Keefe) writes:
>
>Yes, I *KNOW* that.  That's an excellent argument for having "type while"
>say "while is a keyword" rather than "while is a shell builtin".
>It is *NOT* an argument for having "type while" say "while not found".

	(From within vi)
	r!type while
while is a keyword
	r!type for

for is a keyword

	This is with ksh version 88b on i386.

	-randy
-- 
Randy Suess
randy@chinet.chi.il.us

ruud@targon.UUCP (Ruud Harmsen) (01/04/90)

In article <1297@quintus.UUCP> ok@quintus.UUCP (Richard A. O'Keefe) writes:
>Does anyone know why the C shell command "which" (ok, /usr/ucb/which)
>and the Bourne shell command "type" don't understand built-in commands?
> [stuff deleted]
>
>This certainly looks to me as though "type if" SHOULD succeed, and
>"type type" _does_.  So why does "type while" say "while not found"
>rather than "while is a shell builtin"?

The point is that "if", "while" etc. are keywords, i.e. lexical units that
make the syntax of the shell command language.  They do not do anything
themselves, but rather control the way other things are done, or going to
be done.

"cd", "type" and (often) "test" etc. are commands that perform some action,
and which happen to have been implemented without creating a separate process.
(In the case of "cd", it has to be, in the other cases, speed is probably
the only reason).

So I would not object to type recognizing "while", but then as a keyword,
not as a builtin *command*.

gwyn@smoke.BRL.MIL (Doug Gwyn) (01/05/90)

In article <1297@quintus.UUCP> ok@quintus.UUCP (Richard A. O'Keefe) writes:
>This certainly looks to me as though "type if" SHOULD succeed, and
>"type type" _does_.  So why does "type while" say "while not found"
>rather than "while is a shell builtin"?

"while" is neither a command nor a builtin; it's a keyword in the shell
programming language.

"type" does have some deficiencies, which is why in the BRL Bourne shell
we implemented the 8th Edition UNIX "whatis" and "builtin" commands.