[comp.unix.questions] why does this script...

daveb@rtech.UUCP (06/15/87)

As Doug Gwyn noted, the Bourne shell ':' is a command, not a comment
character.  However, it is still what I suggest you put in the head of
your  shell scripts for maximum portability.

It's clear you can't have a '#', because that implies csh on some kernels.
You can't rely on '#!/bin/sh', because some kernels don't undertand it.
(Yes, there are some that recoginize '#', but not '#!/...").

One option is to put a blank line at the beginning, which will result in
Bourne shell execution.  Unfortunately, blank lines have an annoying
habit of being removed when someone casually edits a file.
			----------------
easy to lose this line->
			# submit -- run cmd in background, it's output to OUT
			nohup $* > OUT 2>&1 &

If you put a ':' on the first line, WITH NOTHING ELSE, you won't
accidentally delete the line and you will get /bin/sh.  Why ':'?  Because
it's easy to type, innocuous, and usually a built-in making it cheap to
use.
			----------------
harder to lose this---->:
			# submit -- run cmd in background, it's output to OUT
			nohup $* > OUT 2>&1 &

You are asking for trouble if you put comments on the line with the ':'

			----------------
NO NO NO--------------->: submit -- run cmd in background, it's output to OUT
			nohup $* > OUT 2>&1 &


-dB
-- 
{amdahl, cbosgd, mtxinu, ptsfa, sun}!rtech!daveb daveb@rtech.uucp

chris@mimsy.UUCP (06/15/87)

In article <913@rtech.UUCP> daveb@rtech.UUCP (Dave Brower) writes:
>... You are asking for trouble if you put comments on the line with the ':'
>		: submit -- run cmd in background, it's output to OUT
>		nohup $* > OUT 2>&1 &

Of course, if you spell `its' correctly, this particular comment
works after all :-) .  In scripts for export, I use

	: Run this script with "sh" not "csh"

as the first line.
-- 
In-Real-Life: Chris Torek, Univ of MD Comp Sci Dept (+1 301 454 7690)
Domain:	chris@mimsy.umd.edu	Path:	seismo!mimsy!chris

john@xanth.UUCP (06/16/87)

In article <913@rtech.UUCP>, daveb@rtech.UUCP (Dave Brower) writes:
> It's clear you can't have a '#', because that implies csh on some kernels.
> You can't rely on '#!/bin/sh', because some kernels don't undertand it.
> (Yes, there are some that recoginize '#', but not '#!/...").

You say "kernels" above, but I hope you mean "distributions of UNIX
operating systems" or something like that.  The whole point of #! is
that the ->kernel<- understands it and runs the specified interpreter,
as opposed to just the # which the ->csh<- understands to mean "use
the csh", and the newer Bourne shells just consider a comment.

So yes, it's certainly true that there are plenty of versions of UNIX
out there where the kernel does not understand #! but the csh
understands # - all version of System V with the csh, for example.
(If there are System V kernels that do #!, please let me know!)

I think we should end this discussion with a quick summary of the
situation.  Here is a table describing which shell your script will be
run by, depending on what it begins with, and where you're running it
from.  The "sh" here is a Bourne shell that uses "#" as a comment; if
not, the situation's even worse.

script			r u n   f r o m
begins	  kernel knows #!		kernel does not know #!
with	  sh	      csh		sh		csh

#!	-- specified script --		sh		csh

#	  sh	      csh		sh              csh

other	  sh	      sh		sh		sh
(includ-
ing :)

So if you're writing a csh script, the best you can do is to start it
with #! /bin/csh and hope no one tries to run it from the Bourne shell
under a kernel that does not know #!.  If you're writing a Bourne
shell script, you should start it with something else, like a colon
alone on the line, as Dave suggests, and it will always be run by sh.
Only if you know the script will never go to a system that does not
know #! should you use #!/bin/sh .


-- 
John Owens		Old Dominion University - Norfolk, Virginia, USA
john@ODU.EDU		old arpa: john%odu.edu@RELAY.CS.NET
+1 804 440 4529		old uucp: {seismo,harvard,sun,hoptoad}!xanth!john

dhesi@bsu-cs.UUCP (06/16/87)

In several articles strategies for ensuring execution by a specific shell
are discussed.

Larry Wall's terrific installation scripts for patch and rn use the
equivalent of following line to force execution by sh:

     export PATH || (echo "OOPS, trying again..."; sh $0; kill $$)

There ought to be a way of doing the same thing for other shells.  The
penalty is the extra fork (or is it TWO extra forks?).

Perhaps somebody could publish a patch to SVR3's shared library so the
exec family of system calls/functions will test for #!, and modify the
text of the requested command, before passing control to the kernel?
-- 
Rahul Dhesi         UUCP:  {ihnp4,seismo}!{iuvax,pur-ee}!bsu-cs!dhesi

jerry@oliveb.UUCP (06/20/87)

The important thing to remember when using : in sh is that it is a null
command not a begin comment character.  So the following gotchas apply:

      -	The ":" must be followed by a white space or a sh metacharacter.

	: this is ok
	:>fu is also ok but will create the file fu
	:this is not ok because it looks for the command ":this".

      - The rest of the line will undergo normal filename, variable, and
	other metacharacter expansion.  So:

	    : Do I need this line?

	will fail when it tries to glob the question mark (assuming you
	don't have some 5 character file names that start with "line").
	Also, as previously mentioned the quotes must be balanced,
	perentheses have special meaning, etc.

      - A simicolon will end it, not just the end of line.

	    : This is ok; But this will try to execute "But"

It is safest to enclose the entire line in single quotes ala:

	    : 'this allows you to use ?()*$<>; without problems'

The only problem that leaves you is figuring out why:

	    : 'This line won't work'

If you think of : as being a faster version of:

	    /bin/echo>/dev/null arguments used but discarded

You will have a lot less problems.  Also interesting is that the :
command always returns true so it is also a faster replacement for
/bin/true.  With a little work it can also replace /bin/false.

			Jerry Aguirre

P.S.
    It is amazing the number of "experienced" shell programers who get
confused looks when faced with a syntax like.

		<inputfile grep pattern >outputfile

wcs@ho95e.ATT.COM (Bill.Stewart) (06/23/87)

In article <767@bsu-cs.UUCP> dhesi@bsu-cs.UUCP (Rahul Dhesi) writes:
: In several articles strategies for ensuring execution by a specific shell
: are discussed.
: Larry Wall's terrific installation scripts for patch and rn use the
: equivalent of following line to force execution by sh:
:      export PATH || (echo "OOPS, trying again..."; sh $0; kill $$)
: There ought to be a way of doing the same thing for other shells.  The
: penalty is the extra fork (or is it TWO extra forks?).

I generally write all my scripts in Bourne Shell, because I know they'll work
(relatively) portably.  When it's important to use ksh, I use the following:
	if [ "$RANDOM" = "$RANDOM" ] 
	then ## recovery script to feed itself to ksh
		ksh -c "$0 $*"
		exit "$?"
	fi

The simpler approach of checking $SHELL doesn't work; SHELL is exported,
and some programs will drop into /bin/sh by default.  ksh updates $RANDOM each
time it uses the value, so "$RANDOM" = "$RANDOM" will never be true in ksh, and
will (presumably) always be true in other shells.

Writing a good recovery script is hard; if the arguments to the program contain
white space or metacharacters, the $* will trash them.  Sometimes it matters.

Is there a good equivalent of this technique for csh?  I suppose one could
separate the program in to a csh file and a Bourne-shell front-end,
	:
	exec csh -c "$0.csh $*"
but it would be much nicer to have something self-contained.
-- 
# Bill Stewart, AT&T Bell Labs 2G-202, Holmdel NJ 1-201-949-0705 ihnp4!ho95c!wcs