[comp.sources.d] Perl scripts on systems without "#!"

chip@ateng.com (Chip Salzenberg) (11/03/89)

[Note the cross-posting; send followups to the appropriate group.]

According to pvo3366@sapphire.OCE.ORST.EDU (Paul O'Neill):
[Quoting the Perl manual:]
>
>               #!/usr/bin/perl
>               eval "exec /usr/bin/perl -S $0 $*"
>                    if $running_under_some_shell;
>

As the inventor of the "eval exec" hack, I have three comments:

  1.  Some systems don't permit a Bourne shell script to begin with "#".
      Xenix, for example.  When using "eval exec" on a Xenix system, the
      "#!" line must be omitted.

  2.  The "$*" hack is not good.  It's universally available, but it's
      broken in the face of arguments with imbedded spaces or other
      strangeness.  A better choice is "$@", which quotes each argument.
      Due to an old bug in some shells, this must be spelled ${1+"$@"}.

  3.  Larry was a nice guy to add the -S flag just for me.  :-)

Therefore, all Perl scripts on my system begin with these two lines:

    eval 'exec /bin/perl -S $0 ${1+"$@"}'
       if $running_under_some_shell;

I have yet to extend this method in a way that works for the C shell.  If I
could do so, then starting the script with "#!" would work on Xenix.  Does
anyone out there have an idea?
-- 
You may redistribute this article only to those who may freely do likewise.
Chip Salzenberg at A T Engineering;  <chip@ateng.com> or <uunet!ateng!chip>
"'Why do we post to Usenet?'  Naturally, the answer is, 'To get a response.'"
                        -- Brad "Flame Me" Templeton

tneff@bfmny0.UU.NET (Tom Neff) (11/03/89)

In article <255072E0.20005@ateng.com> chip@ateng.com (Chip Salzenberg) writes:
>Therefore, all Perl scripts on my system begin with these two lines:
>
>    eval 'exec /bin/perl -S $0 ${1+"$@"}'
>       if $running_under_some_shell;
>
>I have yet to extend this method in a way that works for the C shell.  If I
>could do so, then starting the script with "#!" would work on Xenix.  Does
>anyone out there have an idea?

According to my notes, CSH looks for a colon ':' as the first token
in a script and passes it on to /bin/sh if the colon is seen.  So perhaps

	:
    eval 'exec /bin/perl -S $0 ${1+"$@"}'
       if $running_under_some_shell;

would do the trick.  But the problem here is that PERL hates the colon!
So you could set up a script like this for script execution, but not
feed it to perl unmodified.

Perl being still under modification, perhaps it could be fixed to accept
this.  Or is there a clever perl-ism that would let us put the colon there.
-- 
I'm a Leo.  Leos don't believe    *  *  *     Tom Neff
    in this astrology stuff.        *  *  *   tneff@bfmny0.UU.NET

allbery@NCoast.ORG (Brandon S. Allbery) (11/05/89)

As quoted from <1989Nov4.180708.26446@NCoast.ORG> by allbery@NCoast.ORG (Brandon S. Allbery):
+---------------
| Actually, csh looks for # as the first character of a script and passes it to
| sh if it doesn't find the #.
+---------------

If csh fails to exec() a program, it checks for an alias called "shell" and,
if found, prepends the value of the alias to the command and re-exec()'s it.
You can not use any of the standard alias/history modifiers and the program
called by the alias must be a full pathname.

Here's a program which I've compiled and tested, which uses the "alias shell"
approach.  Compile it, install it somewhere, and alias "shell" to the full
pathname of the executable, then enjoy a working #! and not having to worry
about the wrong shell executing your scripts.  I used to have a program called
"bexec" which purported to do this, but various versions did not work right or
took the wrong approach, or did more than most people really need (like
attempting to recognize RM/COBOL objects).  This is simpler and cleaner.

++Brandon

-------------------------------------------------------------------------------
#include <stdio.h>

#define SHELL		"/bin/sh"

extern void exit();
extern FILE *fopen();
extern void perror();
extern int fclose();
extern char *fgets();
extern int fprintf();
extern char *malloc();
extern int execve();

main(argc, argv, envp)
    char **argv, **envp;
{
    FILE *fp;
    char hashbang[1024];
    register char *cp;
    int nargc;
    char **nargv;

    if (argc < 2)
	exit(-1);
    if (!(nargv = (char **) malloc((argc + 2) * sizeof *nargv)))
    {
	perror(argv[1]);
	exit(-1);
    }
    if (!(fp = fopen(argv[1], "r")))
    {
	perror(argv[1]);
	exit(-1);
    }
    if (!fgets(hashbang, sizeof hashbang, fp))
    {
	(void) fclose(fp);
	(void) fprintf(stderr, "%s: cannot read\n", argv[1]);
	exit(-1);
    }
    (void) fclose(fp);
    if (hashbang[0] != '#' || hashbang[1] != '!')
    {
	argv[0] = SHELL;
	(void) execve(SHELL, argv, envp);
	perror(SHELL);
	exit(-1);
    }
    for (cp = hashbang + 2; *cp && *cp == ' '; cp++)
	;
    if (!*cp)
    {
	(void) fprintf(stderr, "%s: malformed #! line\n", argv[1]);
	exit(-1);
    }
    nargc = 1;
    for (nargv[0] = cp; *cp && *cp != ' ' && *cp != '\n'; cp++)
	;
    if (*cp)
	*cp++ = '\0';
    while (*cp == ' ')
	cp++;
    if (*cp && *cp != '\n')
    {
	nargv[nargc++] = cp;
	while (*cp && *cp != '\n')
	    cp++;
	*cp = '\0';
    }
    for (; argc; argc--)
	nargv[nargc + argc - 1] = argv[argc];
    (void) execve(nargv[0], nargv, envp);
    perror(nargv[0]);
    exit(-1);
}
-- 
Brandon S. Allbery    allbery@NCoast.ORG, BALLBERY (MCI Mail), ALLBERY (Delphi)
uunet!hal.cwru.edu!ncoast!allbery ncoast!allbery@hal.cwru.edu bsa@telotech.uucp
*(comp.sources.misc mail to comp-sources-misc[-request]@backbone.site, please)*
*Third party vote-collection service: send mail to allbery@uunet.uu.net (ONLY)*
>>>	     The *.aquari* debate: news.groups gone news.playpen	    <<<

wcs) (11/10/89)

In article <25524424.5307@ateng.com> chip@ateng.com (Chip Salzenberg) writes:
]>     :
]>     eval 'exec /bin/perl -S $0 ${1+"$@"}'
]>        if $running_under_some_shell;
]>(Larry Wall)>I taught perl to ignore a leading : on the first line.

]The reason I want a C shell hack that works like "eval exec" is because I'd
]like to keep the #! as the first line.  Shell scripts that start with 
]the #! are considered C shell scripts on systems where #! doesn't work.

	WRONG!!  Most System V systems do not support the #! hack.
	Most System V systems consider shell scripts to be Bourne
	Shell scripts, though some csh implementations will try to
	run them as csh scripts.  But please don't depend on this -
	many people use either sh or ksh, and csh scripts are useless!
	People who prefer to use csh as their shell can always feed
	things to /bin/sh.

	What is really needed here is a 3-language hack, for
	perl, csh, and sh.  The suggestion you give below won't work
	- the set noglob changes $* to "noglob", which is boring.
	Is the noglob really needed?  Would "$@" do instead of $*?

]	#!/bin/perl
]	##_PERL_IGNORE_NEXT_LINE_##
]	set noglob; exec /bin/perl -S $0 $*
]	# Commence Perl

	What does a #! system do if perl is somewhere other than /bin?
-- 
# Bill Stewart, AT&T Bell Labs 4M312 Holmdel NJ 201-949-0705 api.att.com!wcs

#		.... rainbow's end down that highway ....

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

Brandon Allbery's "alias shell" hack works wonderfully on System V and
System III based Xenix. I think that pretty much solves the problem
for interactive use. How to hack the bourne shell to work that way is
another question.
-- 
`-_-' Peter da Silva <peter@ficc.uu.net> <peter@sugar.hackercorp.com>.
 'U`  --------------  +1 713 274 5180.
"*Real* wizards don't whine about how they paid their dues"
	-- Quentin Johnson quent@atanasoff.cs.iastate.edu

chip@ateng.com (Chip Salzenberg) (11/12/89)

Oh, please.  Calm down, Bill, and read carefully before following up.

According to wcs@cbnewsh.ATT.COM (Bill Stewart):
>]The reason I want a C shell hack that works like "eval exec" is because I'd
>]like to keep the #! as the first line.  Shell scripts that start with 
>]the #! are considered C shell scripts on systems where #! doesn't work.
>
>   WRONG!!  Most System V systems do not support the #! hack.

Of course.  I never asserted otherwise.

>   Most System V systems consider shell scripts to be Bourne
>   Shell scripts, though some csh implementations will try to
>   run them as csh scripts.

In my experience, all Unix vendors that include the C shell have modified
their Bourne and C shells to use some consistent rule to determine the
flavor of a given script.  Also, as far as I know, all systems with a C
shell and without "#!" consider an initial "#" to signify a C shell script.
This decision is the same regardless of the shell doing the examination.

>   What is really needed here is a 3-language hack, for perl, csh, and sh.
>

You're quite right, for once.  Unfortunately, your streak doesn't hold:

>   The suggestion you give below won't work
>   - the set noglob changes $* to "noglob", which is boring.

Oh, Bill.  You've given yourself away as being ignorant of the C shell.

The command "set noglob" sets the "noglob" shell variable to a value of "",
which has the side effect of disabling filename globbing.  So "set noglob;
echo *" _always_ prints "*".  Setting noglob is required if "/bin/perl -S $0
$argv" is to work properly.

>   Is the noglob really needed?

Yup.

>       Would "$@" do instead of $*?

Nope.

allbery@NCoast.ORG (Brandon S. Allbery) (11/12/89)

As quoted from <6928@ficc.uu.net> by peter@ficc.uu.net (Peter da Silva):
+---------------
| Brandon Allbery's "alias shell" hack works wonderfully on System V and
| System III based Xenix. I think that pretty much solves the problem
| for interactive use. How to hack the bourne shell to work that way is
| another question.
+---------------

You could always hack it into bash...  For the purposes of perl, I use the
standard trickery.  Unfortunately, convincing sh or ksh to even consider an
outside program to do the work a' la csh's "alias shell" requires source.

++Brandon
-- 
Brandon S. Allbery    allbery@NCoast.ORG, BALLBERY (MCI Mail), ALLBERY (Delphi)
uunet!hal.cwru.edu!ncoast!allbery ncoast!allbery@hal.cwru.edu bsa@telotech.uucp
*(comp.sources.misc mail to comp-sources-misc[-request]@backbone.site, please)*
*Third party vote-collection service: send mail to allbery@uunet.uu.net (ONLY)*
expnet.all: Experiments in *net management and organization.  Mail me for info.

wcs) (11/20/89)

Chip posted an article about a perl hack to make csh feed the script
to perl on systems that don't handle #!/bin/perl on the first line.
I followed up pointing out that this will fail miserably for people
whose systems don't feed shell scripts to C shell.

In article <255C7F44.171@ateng.com> chip@ateng.com (Chip Salzenberg) writes:
] According to wcs@cbnewsh.ATT.COM (Bill Stewart):
] > ] like to keep the #! as the first line.  Shell scripts that start with 
] > ] the #! are considered C shell scripts on systems where #! doesn't work.
] > WRONG!!  Most System V systems do not support the #! hack.
] Of course.  I never asserted otherwise.
	You asserted that systems which don't support #! support the
	# => C shell convention.  Vanilla System V systems do not
	do either one, and are thus a major counterexample.

] In my experience, all Unix vendors that include the C shell have modified
] their Bourne and C shells to use some consistent rule to determine the
] flavor of a given script.  Also, as far as I know, all systems with a C
] shell and without "#!" consider an initial "#" to signify a C shell script.
] This decision is the same regardless of the shell doing the examination.
	You experience is too limited :-).  On conventional System V systems,
	the C shell generally will assume initial # means C shell,
	but the Bourne Shell (and Korn Shell) follow correct syntax,
	which is that # is simply a Bourne-shell comment.

	The decision that # means C shell was made back when the
	alternative was V6 Mashey shell (maybe also very early Bourne?),
	which used : for the eval-and-ignore statement and didn't
	have a true comment.  But this is only supported on Berkeley
	systems and systems whose vendors have decided to break
	conforming Bourne shell programs to enhance C shell support.
	Using #!/bin/csh as an indicator that the user really wants
	csh isn't too bad, since it isn't a comment that people
	would put at the beginning of most Bourne Shell scripts.

] >   What is really needed here is a 3-language hack, for perl, csh, and sh.
] You're quite right, for once.  
	Always, Chip, Always!  :-)
] >   The suggestion you give below won't work
] >   - the set noglob changes $* to "noglob", which is boring.
] Oh, Bill.  You've given yourself away as being ignorant of the C shell.
	No, you've lost context at this point.  I had just argued
	that standard behavior for System V and other "proper" systems
	is to use Bourne Shell for shell scripts, in the absence of #!,
	and therefore the discussion is in the context that the
	script might find itself being run by /bin/sh, csh, or perl.
	Perhaps I should have been more explicit about the fact that
	I was describing what your hack would do if fed to /bin/sh,
	but my comment is correct about what /bin/sh (and ksh) does
	with a "set noglob" statement, and was checked on several
	different Bourne shell implementations.
	
] Setting noglob is required if "/bin/perl -S $0 $argv" is to work properly.
	Too bad - if you didn't need to set noglob, or could find a
	hack that tells csh to set noglob and does something
	innocuous in /bin/sh, we might have a working 3-language hack,
	since both shells will handle the exec correctly (assuming
	perl is in /bin/perl, which is often not valid.)

] Oh, please.  Calm down, Bill, and read carefully before following up.
	That *was* calm, more or less, and I think I had read it carefully.
	I simply have a different worldview than yours, and come to
	different conclusions from reading what you wrote :-).
	Remember that not everyone uses, or even likes csh!
	Systems that do support it don't always treat it specially.

				Bill
-- 
# Bill Stewart, AT&T Bell Labs 4M312 Holmdel NJ 201-949-0705 api.att.com!wcs

#		We did it for the formlessness ...

chip@ateng.com (Chip Salzenberg) (11/21/89)

According to wcs@cbnewsh.ATT.COM (Bill Stewart):
>You asserted that systems which don't support #! support the
># => C shell convention.  Vanilla System V systems do not
>do either one, and are thus a major counterexample.

I stand corrected.

>On conventional System V systems, the C shell generally will assume
>initial # means C shell, but the Bourne Shell (and Korn Shell) follow
>correct syntax, which is that # is simply a Bourne-shell comment.

With that "correct syntax" remark, I see why the Organization: line of
the quoted article read "Committee to Insult the C Shell".  :-)

After discussion, it seems that a script can be identified in only one
portable way:

	A script with ":" as the first character
	   is always run by the Bourne shell.

Anything else is non-portable.  Am I right?
-- 
You may redistribute this article only to those who may freely do likewise.
Chip Salzenberg at A T Engineering;  <chip@ateng.com> or <uunet!ateng!chip>
    "Did I ever tell you the Jim Gladding story about the binoculars?"

tneff@bfmny0.UU.NET (Tom Neff) (11/21/89)

In article <2568811E.264@ateng.com> chip@ateng.com (Chip Salzenberg) writes:
>After discussion, it seems that a script can be identified in only one
>portable way: A script with ":" as the first character is always run by
>the Bourne shell. Anything else is non-portable. Am I right?

Not really...

Korn shell (with the default "SHELL=/bin/ksh" set) will execute a script
with ":" as the first character under Korn rather than Bourne.  Of course,
if you're sure it's one of Korn OR Bourne, the $RANDOM trick will pick 'em.

The bottom line is there's no portable standard.  BSD mavens get so used
to their #! hack they assume it's universal, but it ain't.

I suspect there's an elegant hack though, I just haven't thought of it.
-- 
"Take off your engineering hat   | "The filter has      | Tom Neff
and put on your management hat." | discreting sources." | tneff@bfmny0.UU.NET

peter@ficc.uu.net (Peter da Silva) (11/22/89)

In article <2568811E.264@ateng.com> chip@ateng.com (Chip Salzenberg) writes:
> 	A script with ":" as the first character
> 	   is always run by the Bourne shell.

> Anything else is non-portable.  Am I right?

No. If you have the hashbang program, and !alias shell hashbang! in your
.cshrc, then you can in addition say:

	A script with "#!/bin/sh" as the first line
	is always run by the bourne shell.

And you can use the two-language-hack to solve the problem.
-- 
`-_-' Peter da Silva <peter@ficc.uu.net> <peter@sugar.lonestar.org>.
 'U`  --------------  +1 713 274 5180.
"I agree 0bNNNNN would have been nice, however, and I sure wish X3J11 had taken
 time off from rabbinical hairsplitting to add it." -- Tom Neff <tneff@bfmny0>

chip@ateng.com (Chip Salzenberg) (11/23/89)

According to peter@ficc.uu.net (Peter da Silva):
>If you have the hashbang program, and !alias shell hashbang! in your
>.cshrc, then you can in addition say:
>
>	A script with "#!/bin/sh" as the first line
>	is always run by the bourne shell.

Which is to say, "#!/bin/sh" is not portable, since you cannot count on
_every_ user having "alias shell hashbang" in their .cshrc files.
-- 
You may redistribute this article only to those who may freely do likewise.
Chip Salzenberg at A T Engineering;  <chip@ateng.com> or <uunet!ateng!chip>
    "Did I ever tell you the Jim Gladding story about the binoculars?"

peter@ficc.uu.net (Peter da Silva) (11/29/89)

In article <256B2530.23386@ateng.com> chip@ateng.com (Chip Salzenberg) writes:
> Which is to say, "#!/bin/sh" is not portable, since you cannot count on
> _every_ user having "alias shell hashbang" in their .cshrc files.

You can if you're the system administrator at a site.

Worst case would be: the script doesn't run. User comes to you. You fix
their .cshrc and explain. No problem.

Now for scripts posted to the net, well, that's a different matter. Of
course anyone *running* stuff from the net is likely to be savvy enough
to install hashbang. Or the person who installs the code for them will.
-- 
`-_-' Peter da Silva <peter@ficc.uu.net> <peter@sugar.lonestar.org>.
 'U`  --------------  +1 713 274 5180.
"The basic notion underlying USENET is the flame."
	-- Chuq Von Rospach, chuq@Apple.COM