[comp.sys.att] Forcing /bin/sh in a script under V/386 3.2 Korn shell

tneff@bfmny0.UUCP (Tom Neff) (07/08/89)

I use Korn shell and am happy with it, but I want certain shell
scripts to be intepreted by the Bourne shell instead.  There is
already a mechanism by which CSH(1) figures out to spawn /bin/sh
on a script rather than interpreting itself, namely putting a
colon ':' as the first line.

	% cat > xxx
	:
	ps
	^D
	% chmod a+x xxx
	% xxx
	   PID TTY      TIME COMMAND
	 27632 console  0:00 csh
	 27640 console  0:00 sh
	 27641 console  0:00 ps

What I want to know is, is there any way to do this under K-shell?
The colon certainly doesn't work, and neither does

	#! /bin/ksh

or anything else I've tried.  Sure would be nice.
-- 
"My God, Thiokol, when do you     \\	Tom Neff
want me to launch -- next April?"  \\	uunet!bfmny0!tneff

cks@ziebmef.uucp (Chris Siebenmann) (07/12/89)

In article <14445@bfmny0.UUCP> bfmny0!tneff@uunet.UU.NET (Tom Neff) writes:
| I use Korn shell and am happy with it, but I want certain shell
| scripts to be intepreted by the Bourne shell instead.  

 On a BSD Unix, one could put "#! /bin/sh" at the start of your script
and it would work. Unfortunately, System V doesn't have this (and
worse yet, your vendor has gratuitusly hacked csh so many scripts will
break under it), so the best substitute (swiped from Perl v2's
Configure script) is:

	(alias) >/dev/null 2>&1 && (exec /bin/sh $0 ${1+"$@"})

-- 
	"Oh BLESS you, sir! The ANGEL OF DEATH was after me just as SURE as
	 you're standing there, yes he WAS!"
Chris Siebenmann		uunet!{utgpu!moore,attcan!telly}!ziebmef!cks
cks@ziebmef.UUCP	     or	.....!utgpu!{,ontmoh!,ncrcan!brambo!}cks

trent@cs.dal.ca (Trent MacDougall) (07/13/89)

From article <14445@bfmny0.UUCP>, by tneff@bfmny0.UUCP (Tom Neff):
> I use Korn shell and am happy with it, but I want certain shell
> scripts to be intepreted by the Bourne shell instead.  There is
> already a mechanism by which CSH(1) figures out to spawn /bin/sh
> on a script rather than interpreting itself, namely putting a
> colon ':' as the first line.
> 
> What I want to know is, is there any way to do this under K-shell?
> 

I was just going to send Todd Day this note. His postings about setting
up C News helped me and I wanted to return the favor.  I put the following
at the beginning of the file /usr/local/lib/news/bin/config.

	if [ "$RANDOM" != "$RANDOM" ]
	then
		/bin/sh -c "$0 $*"; exit $?
	fi

This will force all shell scripts to be run under sh instead of ksh.
-- 
//_//_//_//_//  Trent MacDougall @ Dalhousie University, CS Dept.
\\_\\_\\_\\_\\  UUCP               {uunet watmath}!dalcs!trent
// // // // //  INTERNET           trent@cs.dal.ca

tneff@bfmny0.UUCP (Tom Neff) (07/13/89)

My thanks to all who have responded via mail or news posting to my
question about forcing the Korn shell (KSH) to run a script using the
Bourne shell (SH) instead of itself.  There have been no completely
satisfactory answers, but I will summarize the State Of What Is Known.

 * There are a few minor incompatibilities between the way SH and KSH
   behave in a correctly written script, but the biggest reason why
   you would want SH to run a script instead of KSH (if it's simple
   and dumbed down to SH) is that KSH takes a lot longer to fork
   itself.  Thus tricks that let KSH, once forked, realize it should
   hand the reins over to SH (such as [ "$RANDOM" = "$RANDOM" ]) are
   not enough; you not only have to spend the time forking KSH but
   also the time to reinvoke SH.

 * There is an exact analogue to what I want for the C-Shell (CSH):
   if you put a colon ":" as the first line of a script, CSH will
   detect it and automatically spawn SH instead of itself to execute
   the script.  (This is the way AT&T documents it; some users claim
   that putting *anything* other than "#" at the start of the first
   line does it, or that a blank first line does it, but I recommend
   sticking with the AT&T convention to avoid blowing up on someone's
   weird CSH variant.)  You can see this done at the start of most of
   the AT&T supplied system shell scripts like installpkg and shutdown
   and even basename.  But no, it does not convince KSH.  To prove this,
   create the script

	:
	ps -f

 * If you must use one of the "tricks" like Todd Day's $RANDOM thing,
   for the sake of correct (though not faster) script execution, you
   should follow up with "exec" rather than sub-spawning SH underneath
   the KSH process.

	test "$RANDOM" = "$RANDOM" && exec /bin/sh -c $0 $*

   or to force KSH:

	test "$RANDOM" = "$RANDOM" || exec /bin/ksh -c $0 $*

 * Although you can't escape KSH's long fork time (apparently), you can
   definitely escape the potentially lengthy process of glomming your
   ENV environment script for every subshell, by using the ENV trick
   described in the KSH documentation:

	export Envfile=$HOME/.env
	export ENV='${Envfile[(_$-=1)+(_=0)-(_$-!=_${-%%*i*})]}'

   This cryptic mass will run your environment script (presumably
   including your favorite functions and aliases etc., and in this 
   example named ".env" in your home directory) if and only if you 
   spawn an interactive shell, such as a naked "!" from rn(1) or vi(1).  
   If you spawn a command directed subshell, a la "ksh -c echo hi", 
   the environment script won't run and your subprocess will get going
   a whole lot faster.

If anyone has an answer to the original question, operators are still
standing by.  :-)  If no one does, and if Dave Korn (or the fellow who
famously sits right next to him) is listening, an auto-SH convention
in scripts would be a Nice Thing To Have next version of KSH.
-- 
"My God, Thiokol, when do you     \\	Tom Neff
want me to launch -- next April?"  \\	uunet!bfmny0!tneff

ford@cbmvax.UUCP (Michael "Ford" Ditto) (07/13/89)

In article <1989Jul12.191342.1048@cs.dal.ca> trent@cs.dal.ca (Trent MacDougall) writes:
>	if [ "$RANDOM" != "$RANDOM" ]
>	then
>		/bin/sh -c "$0 $*"; exit $?
>	fi
>
>This will force all shell scripts to be run under sh instead of ksh.

Umm ... not quite -- sometimes ksh would still be used, at RANDOM, you
might say (anytime $RANDOM happens to return the same value both times).

The example also trashes the argument list.
-- 
					-=] Ford [=-

"The number of Unix installations	(In Real Life:  Mike Ditto)
has grown to 10, with more expected."	ford@kenobi.commodore.com
- The Unix Programmer's Manual,		...!ucsd!crash!kenobi!ford
  2nd Edition, June, 1972.		ditto@cbmvax.commodore.com

tbertels@cipc1.Dayton.NCR.COM (Tom Bertelson) (07/15/89)

In article <1989Jul11.225839.14835@ziebmef.uucp> cks@ziebmef.uucp (Chris Siebenmann) writes:
> On a BSD Unix, one could put "#! /bin/sh" at the start of your script
>and it would work. Unfortunately, System V doesn't have this (and
>worse yet, your vendor has gratuitusly hacked csh so many scripts will
>break under it), so the best substitute (swiped from Perl v2's
>Configure script) is:
>
>	(alias) >/dev/null 2>&1 && (exec /bin/sh $0 ${1+"$@"})

A minor nit.  If you have an interactive program called "alias" on
your system (as I discovered here) you could be in for a surprise.
Try instead

	(PATH= alias) >/dev/null 2>&1 && (exec /bin/sh $0 ${1+"$@"})

Some day I'll send this off to Larry Wall ...
-- 
Tom Bertelson			DISCLAIMER:  My opinions are my own and
Tom.Bertelson@Dayton.NCR.COM	in no way reflect those of my employer.
...!uunet!ncrlnk!cipc1!tbertels

ned@pebbles.cad.mcc.com (CME Ned Nowotny) (07/19/89)

In article <14463@bfmny0.UUCP> tneff@bfmny0.UUCP (Tom Neff) writes:
>My thanks to all who have responded via mail or news posting to my
>question about forcing the Korn shell (KSH) to run a script using the
>Bourne shell (SH) instead of itself.  There have been no completely
>satisfactory answers, but I will summarize the State Of What Is Known.
>
... Lines Deleted ...
>
> * There is an exact analogue to what I want for the C-Shell (CSH):
>   if you put a colon ":" as the first line of a script, CSH will
>   detect it and automatically spawn SH instead of itself to execute
>   the script.  (This is the way AT&T documents it; some users claim
>   that putting *anything* other than "#" at the start of the first
>   line does it, or that a blank first line does it, but I recommend
>   sticking with the AT&T convention to avoid blowing up on someone's
>   weird CSH variant.)  You can see this done at the start of most of
>   the AT&T supplied system shell scripts like installpkg and shutdown
>   and even basename.  But no, it does not convince KSH.  To prove this,
>   create the script
>
>	:
>	ps -f
>

There is some missing history here.

In the old days (around Version 6 or 7 and before), the Bourne shell did not
have a comment character, but it did have the null command, ":".  Now, the null
command was useful in several ways (e.g. ":" is a trivial true command - this
was important when "true" was not a built-in and required a new process to be
forked).  In fact, one of the most useful things you could do with ":" was to
comment your shell script since ":" does nothing with the arguments (a.k.a.
comment string) that you may provide it.  While modern Bourne shells include
both the "#" comment character and a built-in "true", they also still include
the null command, ":".  As a consequence, the Korn shell also includes the
null command and its original semantics.  So no, it can not be used to
distinguish a Bourne shell script from a Korn shell script.

On the other hand, the C shell did use the "#" as a comment character in
the early days.  As a result, shell scripts that started with a "#" were
almost certainly C shell scripts beginning with a comment (as all good
code should).  Therefore, the C shell could be preferentially forked just
by determining whether the script began with a "#".  While BSD went on to
provide the more general script mechanism using "#!", AT&T never really
did much better than use the old comment character trick.  This even after the
Bourne shell gained the "#" comment character and despite the inclusion
of the C shell by UNIX vendors.  (Of course, AT&T did not include C shell
as part of its stock UNIX distribution for many years, so the conflict was
a non-problem from their point of view.)

So while I can't provide a solution to your problem given that your system
does not support the "#!" mechanism, I hope this history may at least explain
why things are the way they are (mostly, AT&T suffered from NIH - and yes,
BSD suffered from "featuritis").  Errors in the above will no doubt be quickly
corrected.


Ned Nowotny, MCC CAD Program, Box 200195, Austin, TX  78720  Ph: (512) 338-3715
ARPA: ned@mcc.com                   UUCP: ...!cs.utexas.edu!milano!cadillac!ned
-------------------------------------------------------------------------------
"We have ways to make you scream." - Intel advertisement in the June 1989 DDJ.

friedl@vsi.COM (Stephen J. Friedl) (07/19/89)

In article <1792@cadillac.CAD.MCC.COM>, ned@pebbles.cad.mcc.com (CME Ned Nowotny) writes:
> In fact, one of the most useful things you could do
> with ":" was to comment your shell script since ":" does nothing
> with the arguments (a.k.a.  comment string) that you may provide
> it.

While this is true, it can be misleading.  In particular, the line

	cat file file2 > file3

isn't commented out by prefixing it with a colon.  Cat doesn't run,
but redirection *will* take place and file3 will be truncated.

     Steve

-- 
Stephen J. Friedl / V-Systems, Inc.  /  Santa Ana, CA  / +1 714 545 6442 
3B2-kind-of-guy   / {attmail uunet}!vsi!{bang!}friedl  /  friedl@vsi.com

"Why can't I do pointer multiplication in C?" - Blair Houghton

ned@pebbles.cad.mcc.com (CME Ned Nowotny) (07/19/89)

In article <1152@vsi.COM> friedl@vsi.COM (Stephen J. Friedl) writes:
>In article <1792@cadillac.CAD.MCC.COM>, ned@pebbles.cad.mcc.com (CME Ned Nowotny) writes:
=>> In fact, one of the most useful things you could do
=>> with ":" was to comment your shell script since ":" does nothing
=>> with the arguments (a.k.a.  comment string) that you may provide
=>> it.
=>
=>While this is true, it can be misleading.  In particular, the line
=>
=>	cat file file2 > file3
=>
=>isn't commented out by prefixing it with a colon.  Cat doesn't run,
=>but redirection *will* take place and file3 will be truncated.

True.  This is probably one of the reasons an actual comment character (#)
was eventually added to the Bourne shell.


Ned Nowotny, MCC CAD Program, Box 200195, Austin, TX  78720  Ph: (512) 338-3715
ARPA: ned@mcc.com                   UUCP: ...!cs.utexas.edu!milano!cadillac!ned
-------------------------------------------------------------------------------
"We have ways to make you scream." - Intel advertisement in the June 1989 DDJ.

bob@wyse.wyse.com (07/20/89)

In Article 14223 of comp.unix.questions ned@mcc.com (Ned Nowotny)
writes:
<  In article <14463@bfmny0.UUCP> tneff@bfmny0.UUCP (Tom Neff) writes:
<  >My thanks to all who have responded via mail or news posting to my
<  >question about forcing the Korn shell (KSH) to run a script using the
<  >Bourne shell (SH) instead of itself.  There have been no completely
<  >satisfactory answers, but I will summarize the State Of What Is Known.
<  >
<  ... Lines Deleted ...
<  There is some missing history here.
<  
<  In the old days (around Version 6 or 7 and before), the Bourne shell
<  did not have a comment character, but it did have the null command, ":".
<  Now, the null command was useful in several ways ...
 ----lines also deleted----

My apologies as I did not see the original summary that Tom Neff put
out, which may have already included the solution I am sending for
getting ksh to exec sh.  Also, this is my first posting, so if I
have neglected some portion of netiquette, please let me know
via e-mail  :-).  I have also supplied some additional stuff
about uses of the colon command.

As noted, using the colon command for comments is a problem because
of the possible side effects.  I came across the recommendation, in
_Introducing the UNIX System_ by McGilton and Morgan, that it
is best to place single quotes around the arguments to prevent
these side effects.

The colon command is also useful for evaluation of variables, as in
the following:

	: ${CWDIR=`pwd`}

which will set CWDIR to the current directory if CWDIR is not already
set.  If the colon command were not used the shell would then
substitute this name and attempt to execute it as a commend.

With respect to the original question of Tom Neff's, perhaps the
following would help.  It depends on the fact that both _sh_ and
_ksh_ will execute the similar code, while _ksh_ adds some "extras", such
as RANDOM, which _sh_ will treat differently.  In _ksh_ each reference
to RANDOM will cause the value of RANDOM to change.

	if [ "$RANDOM" -eq "$RANDOM" ]
	then
	   # what you want sh to do
	else
	   # exec sh on this script
	   exec /bin/sh `whence $0` "$@"
	fi

The _whence_ builtin generates the full pathname of the current file
(assuming it is in the path) and _sh_ is used to run it.  The original
arguments must also be supplied to this new invocation.  Using the quoted
$@ above (if I understand it correctly), will guarantee that the
form of the arguments on the original command line will be passed
to the new script invocation in exactly the same form.

I picked up the general idea from some _ksh_ examples I saw once,
in _The Wizards Grabbag_ in UNIXWorld, but I am afraid I do not
remember the author, nor do I have the original at hand.  I have
used the method and found that it works as advertised.  (The
original was used to guarantee that _ksh_ was run on the script,
which contained _ksh_ specific code.)

Hope this proves useful :-)
Bob McGowan
Wyse Technology, San Jose, CA
..!uunet!wyse!bob
bob@wyse.com

guy@auspex.auspex.com (Guy Harris) (07/21/89)

 >While this is true, it can be misleading.  In particular, the line
 >
 >	cat file file2 > file3
 >
 >isn't commented out by prefixing it with a colon.  Cat doesn't run,
 >but redirection *will* take place and file3 will be truncated.

Furthermore, it means that the arguments to the ":" command are parsed,
so the shell won't do what you want if you try something like

	:
	: This isn't a comment
	:

(unless you want something rather perverse).

peter@ficc.uu.net (Peter da Silva) (07/23/89)

In article <2264@auspex.auspex.com>, guy@auspex.auspex.com (Guy Harris) writes:
> 	:
> 	: This isn't a comment
> 	:

Perhaps it's time for the Obfuscated Shell Script contest?
-- 
Peter da Silva, Xenix Support, Ferranti International Controls Corporation.
Business: peter@ficc.uu.net, +1 713 274 5180. | "...helping make the world
Personal: peter@sugar.hackercorp.com.   `-_-' |  a quote-free zone..."
Quote: Have you hugged your wolf today?  'U`  |    -- hjm@cernvax.cern.ch

kdb@chinet.chi.il.us (Karl Botts) (07/25/89)

In article <1792@cadillac.CAD.MCC.COM> ned%cad@MCC.COM (CME Ned Nowotny) writes:
>In article <14463@bfmny0.UUCP> tneff@bfmny0.UUCP (Tom Neff) writes:
>>My thanks to all who have responded via mail or news posting to my
>>question about forcing the Korn shell (KSH) to run a script using the
>>Bourne shell (SH) instead of itself.  There have been no completely
>>satisfactory answers, but I will summarize the State Of What Is Known.

Well, let me take a shot: put the following line as the first of any script
you want to run only under ksh, not sh:

2>/dev/null PPID=0 && { echo "$0: korn shell script" 1>&2; exit 1; }

It's awful to look at, but it works.  It's worse to type, and I haven't
figured out any way to put it in a variable or alias or function or
anything.

The rational is this:  using any of the built-in commands which are in ksh
but not sh to detect the difference can never be bulletproof, because a
binary (or whatever) can always be created with the same name as the ksh
built-in, which will do something (who knows what) under sh.  In fact, it
is not a particularly remote possibility that this could happen, because
writing binaries to emulate ksh built-ins is a perfectly reasonable thing
to do.

In fact, there is nothing that ksh can do that sh can't which can be
a bulletproof test, because ksh is supposed to be a superset of sh, and
even though it isn't it is legitimate for future versions to be closer to
being a superset--therefore any failures of super-setness used to make a
test are liable to go away.

What is needed is something which sh can do that ksh can't.  So far as I
can tell by empiric methods there is only one such thing--assign to the
PPID environment variable.  (ksh can assign to RANDOM, PWD and all the
others I tested.)  I think it is reasonable to assume that as long as ksh
implements the PPID envar, it cannot afford to permit it to be changed
(since it cannot change its parent.)  In fact, "typeset -r" reveals that
PPID is the only built-in envar with the R/O attribute.

I will be delighted if someone can improve on this miserable kludge.

ap@cbnews.ATT.COM (Alexis Porras) (07/26/89)

In article <9065@chinet.chi.il.us> kdb@chinet.chi.il.us (Karl Botts) writes:
|
|Well, let me take a shot: put the following line as the first of any script
|you want to run only under ksh, not sh:
|
|2>/dev/null PPID=0 && { echo "$0: korn shell script" 1>&2; exit 1; }
|
 ... more stuff ...
|In fact, there is nothing that ksh can do that sh can't which can be
|a bulletproof test, because ksh is supposed to be a superset of sh, and
 ... more stuff ...
|
|What is needed is something which sh can do that ksh can't.  So far as I
 ... more stuff ...
|I will be delighted if someone can improve on this miserable kludge.

I wasn't going to do it but...put this at the top of your ksh script:

	echo ^false >/dev/null || exec ksh $0 "$@"

(or replace "ksh" by a full path name is ksh is not in the
standard PATH)

Well, that's my contribution to humanity for the week!