[net.unix] "#! /bin/sh" vs ":"

jmm@ski.UUCP (Joel M. Miller) (04/27/85)

There are at least 2 ways of indicating to csh that a Shell script
should be interpreted by sh: begin the file with:

	#! /bin/sh

or with any character other than "#", such as:

	:

These two ways are not equivalent, but I can't characterize the
difference.  The first sometimes causes commands in the script
to fail with the error message "restricted", and produces a funny
command line in ps -f:

	file file

These are cured by ":".

But what's really happening here?
-- 
Joel M Miller; Smith-Kettlewell Institute of Visual Sciences
2232 Webster St; San Francisco CA 94115; 415/561-1703
dual!ptsfa!ski!jmm    OR    {ucbvax,dual,sun}!twg!ski!jmm

tmb@talcott.UUCP (Thomas M. Breuel) (04/29/85)

[the following is valid for Berkley kernels 2.8 and up and 4.1 and up]

> There are at least 2 ways of indicating to csh that a Shell script
> should be interpreted by sh: begin the file with:
> 	#! /bin/sh
> or with any character other than "#", such as:
> 	:

Every executable begins with a magic number which identifies the type
of the executable. '#!' is a magic number which indicates that a command
interpreter should be invoked by the kernel (!) to execute this file.
Sample uses are to invoke a shell on a shell file, or to invoke a
Pascal p-code interpreter on a p-code file. Files beginning with
'#!' can be exec'ed, they can even be suid (although that's not a good
idea). The name of the file being executed is passed as a parameter
to the command interpreter. On 4.1 and up, one (1) more argument
can be handed to the command interpreter (e.g. a flag).

Files beginning with '#!' behave practically like binary files. The shell
just exec's them and never sees them. If, however, the exec fails (because
the file to be executed has an invalid magic number), the shell
(sh or csh) looks at the first character of the file. If it is a '#',
it invokes a 'csh' to interpret it, otherwises an 'sh'. (Note that the
'csh' is the special case, not the 'sh').

						Thomas.

guy@sun.uucp (Guy Harris) (04/30/85)

> There are at least 2 ways of indicating to csh that a Shell script
> should be interpreted by sh: begin the file with:
> 
> 	#! /bin/sh
> 
> or with any character other than "#", such as:
> 
> 	:
> 
> These two ways are not equivalent, but I can't characterize the
> difference.

The first, on 4.xBSD systems, possibly 2.[89]BSD systems, other systems
which have been modified to support the kernel detecting executable
interpreter scripts (I think Masscomp's system does so), and systems where
the C shell has been modified to recognize "#!" comments, causes the kernel
(in most cases) to execute the program whose pathname is given after the
"#!", with the zeroth argument (i.e., command name) and first argument which
are both the pathname of the script.

The second, on 4.xBSD systems, possibly 2.[89]BSD systems, and on most other
systems running the C shell, causes the C shell to run "/bin/sh" on the
script.  WARNING: beginning with ':' is NOT a necessary condition for being
a Bourne shell script.  The 4.xBSD Bourne shell, and the System III and V
Bourne shells (as well as, I presume, the Korn shell) permit "#" comments
which are real comments, not no-op commands.

> The first sometimes causes commands in the script to fail with the
> error message "restricted"

This is because some versions of the Bourne shell look at their zeroeth
argument (which, in most cases, is their own path name) to see if it
contains the letter 'r' anywhere, or in the better shells only in the last
component of the path name (so being in "/usr/bin" won't confuse them).  If
it does, it considers itself a "restricted" shell and forbids all sorts of
things, like commands with '/' in their name, changing PATH, redirecting
output, etc..

> and produces a funny command line in ps -f:
> 
> 	file file

This is because, as mentioned, both the zeroth and first arguments to
"/bin/sh" are the name of the file.

	Guy Harris

roger@rtech.ARPA (Roger Rohrbach) (05/11/85)

> But what's really happening here?

	The "#!/bin/sh" trick only works on 4.2BSD and derivatives;
it's actually a magic number for the execve() system call, and is a
generalized way of invoking the correct interpreter for a file.  In
other words, a Franz Lisp program in a file named "prog" which  has
been made executable and which starts with the line:

		#!/usr/ucb/lisp

can be run by typing "prog".
	If you are running csh on a non-BSD Unix system, the  way to
ensure that a file is interpreted by /bin/sh is to make certain that
its first character is not a '#'.  Even a file beginning "#!/bin/sh"
will not be interpreted by sh on such a system, since this is simply
an ordinary comment.  Alternatively, if you set the 'shell' variable
to "/bin/sh", all shell scripts will be interpreted by sh.


						Roger Rohrbach

{ucbvax,decvax}!mtxinu!rtech!roger