[net.unix] csh misconceptions

buck%nrl-css@sri-unix.UUCP (02/26/84)

From:  Joe Buck <buck@nrl-css>


There's been a good deal of misinformation on this list about csh and
the "#!" construction.

First off, 4.xbsd uses sh, not csh, to execute all shell scripts UNLESS
the first line is "#! /bin/csh". Therefore a first line of "#! /bin/sh"
is not necessary. Second, originally a line starting with a colon was
a comment, so sh on some systems does not consider "#" a comment character.
Therefore the suggestion that all users include #!/bin/sh in their shell
scripts is not only unnecessary for portability, but counterproductive.

By the way, on Berkeley systems, any program, not just sh and csh, may
be specified in the first line with "#!". There are some restrictions
though; the full pathname must be given and the command must be less
than 32 characters. There are other restrictions also. This feature is
in the kernel, not the shells. The whole file, including the first line,
is the input for the command, so the command must treat "#" as a comment
character.

-Joe

edhall%rand-unix@sri-unix.UUCP (02/27/84)

From:  Ed_Hall <edhall@rand-unix>

One point that Doug hinted at but didn't comment on explicitly:  All
other things being equal, it is more efficient to use the `#!' construct.

One minor clarification: the `#!' passes the file name to the shell
specified as an argument, not as the standard input.  One argument
is allowed to preceed this, and is whitespace-separated from the shell
path.  Thus:

		#! /bin/csh -f

will, if at the top of `/bin/frebus', cause the command `frebus' to
behave as if:

		/bin/csh -f /bin/frebus

was the actual command.

		-Ed Hall
		edhall@rand-unix        (ARPA)
		decvax!randvax!edhall   (UUCP)

rpw3@fortune.UUCP (03/02/84)

#R:sri-arpa:-1695300:fortune:26900028:000:1095
fortune!rpw3    Mar  2 01:36:00 1984

We run 4.1 on our VAX and I prefer /bin/sh for Shell scripts. My scripts
obey rule (4) of the previous article, i.e., no comment. Usually I am
setting some variables, so no special action is needed. When the script
DOES start with comment, it ends up looking like:

	: 'This is a forced "comment" in all Bourne Shells and is safe'
	# rest of
	# comments...

The first line is "safe", since evaluating a single-quoted thing is o.k.

The only time I use the #!/bin/sh hack is when I NEED the setuid.
Note: If EVERYBODY did the #! hack, or if ALL kernels allowed setuid
shell scripts, I would use them more often. But since shell scripts
are long-lived, I don't (yet). I have some scripts that moved from
an ONYX to a PDP-11/44 to a 4.1 VAX/780 to a Fortune 32:16 over a period
of three years with no changes. Thanks to 'tar' and 'uucp', the original
dates are even preserved on the files! (Lesson: one-off hacks live forever!)

Rob Warnock

UUCP:	{sri-unix,amd70,hpda,harpo,ihnp4,allegra}!fortune!rpw3
DDD:	(415)595-8444
USPS:	Fortune Systems Corp, 101 Twin Dolphins Drive, Redwood City, CA 94065

steffen@ihu1h.UUCP (Joe Steffen) (03/02/84)

How about just leaving the first line blank?  This works with the 4.1 csh
that was ported to System III and V at our site.

gwyn%brl-vld@sri-unix.UUCP (03/03/84)

From:      Doug Gwyn (VLD/VMB) <gwyn@brl-vld>

Thanks for adding more misinformation to the list.

The 4.2BSD Cshell, assuming it has been compiled with OTHERSH defined
as "/bin/sh" as is normally the case, will do the following when you
attempt to execute a shell script (or anything with execute permission
that does not have a "magic number" flagging it as an executable
machine-code binary image):

(1)  The kernel is asked to execv() it.  One of two things can happen:

	(a)  If the script starts with #!progname etc. then the kernel
	arranges for the script to be attached to the standard input of
	the specified program, typically /bin/sh or /bin/csh, which
	takes it from there.

	(b)  Otherwise, the execv() returns to the Cshell with an
	ENOEXEC error indication.

(2)  If there is an alias defined for "shell", then the Cshell will
prepend that to the command and try another execv().

(3)  Otherwise, if the first character of the script is a # character,
the shell specified in the "shell" environment variable is prepended,
or if there is none specified "/bin/csh" is used.  This would usually
be /bin/csh for most Cshell users.  The resulting command is execv()ed.

(4)  Otherwise, OTHERSH (normally /bin/sh) is prepended and execv()ed.

>From the above, it is clear that the ONLY way to ensure that a Bourne
shell script is interpreted by /bin/sh as intended is to supply the
first line

	#!/bin/sh

as I originally said.

Item (3) is pretty silly since most Bourne shell scripts these days
start with a # comment line.

The # comment has been in the Bourne shell since at least 1980.  The
: form is NOT A COMMENT although people used it as one since there
was no true comment until # was added to the shell syntax.  The 6th
Edition UNIX shell used : at the beginning of a line followed by a
label to support "goto label", but it didn't take long for people to
realize that the label could actually be a comment instead.  The
trouble with this is that the Bourne shell EVALUATES the line after
the : command, so one could get "syntax errors" and so forth unless
the comment were quoted.  (Incidentally, the : command does nothing
and returns a 0 exit code, so
	while	:
	do	..stuff..
	done
is a fast way to do a "forever" loop.)

The Bourne shells shipped with 4.2BSD, UNIX System III, and UNIX
System V all support # comments.  Anyone with an older version has a
pretty buggy shell and should upgrade anyway.

...That's what I get for trying to give brief advice instead of a
lengthy treatise...

lcc.bob%ucla-locus@sri-unix.UUCP (03/09/84)

From:            Bob English <lcc.bob@ucla-locus>

Face it, the only way to specify IN THE SCRIPT which interpreter
you want is to use "#! prog" on a BSD system.  Any other method
depends on the vagaries of the shell the user (NOT the
programmer) is running, and is out of the programmer's control.
If shell scripts always depend on the user's shell for
correctness, there is no way to write a reliable shell script
and still allow user specifiable shells.  Period.  And the
failure to provide some mechanism to do so is a serious
shortcoming in standard Unix.

--bob--

P.S. The mechanism to provide the #! interpretation gobbles up
about 50 lines of code in 4.1bsd.

rml@hp-dcd.UUCP (03/20/84)

Suppose  I run csh as my login  shell on a  non-Berkeley  system,  and I
execute a script beginning with

#!/bin/sh

The following steps (as you have outlined) will occur:

>> (1)  The kernel is asked to execv() it.  One of two things can happen:
>> 
>> 	(a)  If the script starts with #!progname etc. then the kernel
>> 	arranges for the script to be attached to the standard input of
>> 	the specified program, typically /bin/sh or /bin/csh, which
>> 	takes it from there.

1b applies only to Berkeley systems; it does not apply here, so we continue to

>> 
>> 	(b)  Otherwise, the execv() returns to the Cshell with an
>> 	ENOEXEC error indication.
>>
>> (2)  If there is an alias defined for "shell", then the Cshell will
>> prepend that to the command and try another execv().

The person who has aliased shell has taken control over which shell will
be executed  away from the script.  This  requires a specific  action on
the part of that person.  Assume this is not the case.

>> (3)  Otherwise, if the first character of the script is a # character,
>> the shell specified in the "shell" environment variable is prepended,
>> or if there is none specified "/bin/csh" is used.  This would usually
>> be /bin/csh for most Cshell users.  The resulting command is execv()ed.

This is the case which takes place.  Since this is a login shell, Cshell
has set its "shell" environment varibale to /bin/csh.  The script, which
begins #!/bin/sh, is thus fed to the Cshell.

>> >From the above, it is clear that the ONLY way to ensure that a Bourne
>> shell script is interpreted by /bin/sh as intended is to supply the
>> first line
>> 
>> 	#!/bin/sh

From this  example,  I state  that the ONLY way to ensure  that a Bourne
shell script is  interpreted by /bin/sh as intended is to supply a first
character which is not #.  The #!program is  counterproductive  not only
for backward  compatibility  with versions of sh which don't recognize #
as a comment  character, but for  compatibility  with non-Berkeley  UN*X
systems.  I generally write Bourne shell scripts with a first line like:

:  this is a Bourne shell script not a Cshell script

If someone does invoke this script from the Cshell with shell aliased to
/bin/csh, the Cshell will complain  about the first line.  It recognizes
:  as a goto label, but does not allow it to have arguments.

Because : is not a true comment character, beware of lines like

:  don't invoke with csh

				Bob Lenk
				{hplabs, inhp4}!hpfcla!rml