[comp.sources.d] Using perl without "#!"

chip@ateng.UUCP (Chip Salzenberg) (02/10/88)

Larry Wall's "perl" program is a real gem.  It is, unfortunately, also
difficult to use on systems without the "#!" hack for scripts.  (This is
one case where Berzerkeley Unix has the edge.  :-])

So, here is a way to fake it without "#!":  use one of the commands that
is the same under sh and perl: "eval".  Put this at the top of each perl
script:

	eval "exec /bin/perl $0 $*"
		if (0);

So when sh sees the first line, it executes it; then when perl sees it,
it passes the syntax check, but the if(0) keeps it from being executed.
-- 
Chip Salzenberg                 UUCP: "{codas,uunet}!ateng!chip"
A T Engineering                 My employer's opinions are a trade secret.
       "Anything that works is better than anything that doesn't."

lwall@devvax.JPL.NASA.GOV (Larry Wall) (02/12/88)

In article <184@ateng.UUCP> chip@ateng.UUCP (Chip Salzenberg) writes:
: ...here is a way to fake it without "#!":  use one of the commands that
: is the same under sh and perl: "eval".  Put this at the top of each perl
: script:
: 
: 	eval "exec /bin/perl $0 $*"
: 		if (0);
: 
: So when sh sees the first line, it executes it; then when perl sees it,
: it passes the syntax check, but the if(0) keeps it from being executed.

That's wondrous fair, Chip!  I'm still grinning.

I'd suggest a few improvements, however.  First, the parens around the 0
are unnecessary.  Second, why not make it self-documenting:

 	eval "exec /bin/perl $0 $*"
 		if $running_via_sh;

Third, rather than putting it *instead* of #!/bin/perl, put it after that line
if your sh understands # comments.  That way the script is more portable.

Incidental-like, that /bin/perl reminds me of a complaint that I've been
getting from some people--why a2p always puts #!/bin/perl in the front
of its output when in Configure you've told it to put perl into some other
directory.  The answer is that I want people to be able to write somewhat
portable perl scripts.  I intended that you should always be able to get
to /bin/perl on any machine, even it is just a symbolic link to where the
real perl is stored.  If you look carefully at the Makefile you'll see
that that is what it tries to do.  At least for systems with symbolic links,
this gets us standardization without forcing people to use much storage in
the root partition.  So a2p will continue to spit out #!/bin/perl.

Now I just have to decide if a2p should put the above eval in for systems
without #!.  I do feel sorry for all victims of NIH. 

Larry Wall
lwall@jpl-devvax.jpl.nasa.gov

root@cca.ucsf.edu (Computer Center) (02/12/88)

In article <1291@devvax.JPL.NASA.GOV>, lwall@devvax.JPL.NASA.GOV (Larry Wall) writes:
> The answer is that I want people to be able to write somewhat
> portable perl scripts.  I intended that you should always be able to get
> to /bin/perl on any machine, even it is just a symbolic link to where the
> real perl is stored.

Trying to lock non-standard programs into /bin is a typical hacker's
mistake. Even a program as fine as perl is said to be doesn't belong
in /bin.

Normally, Unix systems have very limited space in the root filesystem
for very good reasons and even if there were space its contents should
remain standardized for each version (at the least).

The appropriate place for such programs is /usr/local/bin with their
support files in /usr/local/lib and their own subdirectories there
if multiple files are required. This isolates the local additions
into a distinct subtree which may be a separate filesystem allowing
more flexible space control.

The virtues of such a structure are obvious; the name /usr/local is
both suggestive and the most widely used convention although not a
formal standard (unless /usr/group has responded to the suggestion).
Setting up this structure makes it easy for users to determine when
they are using programs which they may not find at other installations,
simplifies system administration, and improves reliability.

You only need to go through one system upgrade on a large system where
promiscuous insertion of non-standard programs into assorted parts
of the filesystem structure has been permitted to appreciate firm
enforcement of such a convention.


Thos Sumner       (thos@cca.ucsf.edu)   BITNET:  thos@ucsfcca
(The I.G.)        (...ucbvax!ucsfcgl!cca.ucsf!thos)

OS|2 -- an Operating System for puppets.

#include <disclaimer.std>

skip@skipnyc.UUCP (Skip Gilbrech) (02/12/88)

In article <1291@devvax.JPL.NASA.GOV> lwall@devvax.JPL.NASA.GOV (Larry Wall)
writes:
>I'd suggest a few improvements, however.  First, the parens around the 0
>are unnecessary.  Second, why not make it self-documenting:
>
> 	eval "exec /bin/perl $0 $*"
> 		if $running_via_sh;
>
>Third, rather than putting it *instead* of #!/bin/perl, put it after that line
>if your sh understands # comments.  That way the script is more portable.

Thanks to Chip & Larry for these ideas:  I was planning to suggest to
Larry that he consider hacking perl to get it to ignore a line like:

	exec /bin/perl $0 $*

if it was the first non-comment line in a script, but Chip's way doesn't
require perl changes, is much more clever, & is even cleaner in an off-
white sort of way (:->

I do want to point out some portability problems, though, with leaving
#!/bin/perl as the very first line of the script if you're running
csh under Xenix or (at least one small implementation of) 'real' System V.

Under Xenix, '#!whatever' not only doesn't exec 'whatever', but explicitly
tells csh that it should do this script. From the Xenix csh man page:
"... C shell will execute ... a standard shell if the first character of
a script IS NOT a #".

The same man page from Microport System V/AT reads:
"... C shell will execute ... a 'standard' shell if the first character of
a script IS a ':' or a newline" (my emphasis on IS NOT and IS).

Leaving aside the infuriatingly typical inconsistency, the effect is almost
the same as under Xenix, except that Chip's original idea to begin the
script with 'eval ...' works under Xenix but probably won't under uport
unless there's a blank line before it, since csh doesn't understand 'eval'.
The trick, of course, under both systems is first to get /bin/sh to read the
script, after which everything works fine.

Unfortunately, the recommended way to accomplish this with both systems
(begin the script with ':') isn't appreciated by perl:

	syntax error in file TEST at line 1, next token ":"
	Execution aborted due to compilation errors.

The only thing that seems to make everybody happy is a blank line, but
of course that screws up the '#!' for those systems that use it, so out
comes the editor whenever these files are moved...

If anybody comes up with a way to make shell and (by extension & with
the above hack) perl scripts portable with NO source changes, I'd love
to hear about it!

>Now I just have to decide if a2p should put the above eval in for systems
>without #!.  I do feel sorry for all victims of NIH. 

Please do (include the 'eval', I mean!)...

-- 
Skip Gilbrech                           UUCP: uunet!pwcmrd!skip
PaineWebber, NYC                              attmail!skipnyc!skip

jbuck@epimass.EPI.COM (Joe Buck) (02/14/88)

In article <1150@ucsfcca.ucsf.edu> root@cca.ucsf.edu (Computer Center) writes:
>Trying to lock non-standard programs into /bin is a typical hacker's
>mistake. Even a program as fine as perl is said to be doesn't belong
>in /bin.

Ah, but when Larry Wall gives us a program, it usually becomes a
standard!
:-)
-- 
- Joe Buck  {uunet,ucbvax,sun,<smart-site>}!epimass.epi.com!jbuck
	    Old Internet mailers: jbuck%epimass.epi.com@uunet.uu.net

hakanson@mist.cs.orst.edu (Marion Hakanson) (02/15/88)

In article <1904@epimass.EPI.COM> jbuck@epimass.EPI.COM (Joe Buck) writes:
>In article <1150@ucsfcca.ucsf.edu> root@cca.ucsf.edu (Computer Center) writes:
>>Trying to lock non-standard programs into /bin is a typical hacker's
>>mistake. Even a program as fine as perl is said to be doesn't belong
>>in /bin.
>
>Ah, but when Larry Wall gives us a program, it usually becomes a
>standard!
>:-)

I agree, it probably will be standard.  But anything in /bin is
guaranteed to be lost in the next OS upgrade.  We try to not even
add stuff to /usr/lib around here.  Lately, we even stay out of /etc
as much as possible.

Marion Hakanson         Domain: hakanson@cs.orst.edu
                        CSNET : hakanson%cs.orst.edu@relay.cs.net
                        UUCP  : {hp-pcd,tektronix}!orstcs!hakanson

jra@jc3b21.UUCP (Jay R. Ashworth) (02/17/88)

In article <1150@ucsfcca.ucsf.edu> root@cca.ucsf.edu (Computer Center) writes:
}Trying to lock non-standard programs into /bin is a typical hacker's
}mistake. Even a program as fine as perl is said to be doesn't belong
}in /bin.

To which, in article <1904@epimass.EPI.COM>,
	jbuck@epimass.EPI.COM (Joe Buck) replies:
> Ah, but when Larry Wall gives us a program, it usually becomes a
> standard!

Complete with the obligatory smiley.  Good point, Joe.  Now, the
unidentifiable "computer center" person may or may not know who Larry
Wall *is*, but I think that using the phrase "hacker's mistake" was,
maybe, a little strong?  Personally, now--just my opinion, you
understand--Larry Wall can do just about anything he likes on my
machine.  I've used his programs, looked at his code, etc., and I
think he probably considered the balance between ease of backup, and
maximum portability.

I used the phrase "who Larry Wall *is*..." back up there a ways.  Now,
don't get me wrong, (Larry, ignore this part) I'm not trying to
suggest that Larry is one of the net.deities or anything, (OK, larry,
you can look again :-), but *I* sure couldn't write RN.  Maybe Mr
"computer center" can.  I wish he'd signed his real name.  It sounds
like I'm trying to put him down, there, and I'm not.  I just don't
*know* his name.  Anyway, I follow more news than anyone else I've
ever met, and I didn't recognize the account name at all.  So maybe
he's just new.  A suggestion, sir:  while newness to the network
shouldn't inhibit people from posting their views, take great care
with tone and such when you don't know for certain that you know all
the pertinent facts.

I like the Harlan Ellison quote used in (sorry, hon, I don't remember
your name, I'm so embarrassed)'s .sig:

Everyone is entitled to an *informed* opinion.

I read the net for a year and a half before posting my first article.
And you sir?

-- jra
-- 
Jay R. Ashworth ---+-- The Great Ashworth & ------------+ ...!uunet!codas!
10974 111th St. N. |       Petrillo Production Company  |  !usfvax2!jc3b21!jra
Seminole FL 34648  +-- Gonna hafta face it, I'm addicted to news...-+---------
(813) 397-1859 ----+-- Tampa Bay's Smallest Video Production House -+ :-) !$

mitch@Stride.COM (Thomas Mitchell) (02/18/88)

In article <1150@ucsfcca.ucsf.edu> root@cca.ucsf.edu (Computer Center) writes:
>In article <1291@devvax.JPL.NASA.GOV>, lwall@devvax.JPL.NASA.GOV (Larry Wall) writes:
>> The answer is that I want people to be able to write somewhat
>> portable perl scripts.  I intended that you should always be able to get
>> to /bin/perl on any machine, even it is just a symbolic link to where the
>> real perl is stored.
>Trying to lock non-standard programs into /bin is a typical hacker's
>mistake. Even a program as fine as perl is said to be doesn't belong
>in /bin.

I agree -- programs which are 'locked' in to any given path are
death.  My preference for a default is "/usr/local" and
"/usr/local/lib" as Larry Wall suggests.  But go one step
further.

Select unique environment variables (perhaps: $PERLHOME,
$PERLPATH, $PERLOPTS) test for them and use them if present to
define the location of the binary ($PERLHOME) and if useful a
path ($PERLPATH) to find libraries.  $PERLOPTS can be used to
pass the equivalent of command line options.

This is not excessively difficult to code and can add much to
portability.  In this way only 'perl' need be found by $PATH
'perl' can be a shell script which checks for these environment
variables and can set them and then exec $PERLHOME/PERL arg_list
to load the real binary.

OH Yes -- document them as well :-)

rick@pcrat.UUCP (Rick Richardson) (02/22/88)

In article <717@stride.Stride.COM> mitch@stride.stride.com.UUCP (Thomas Mitchell) writes:
>
>I agree -- programs which are 'locked' in to any given path are
>death.  My preference for a default is "/usr/local" and
>"/usr/local/lib" as Larry Wall suggests.  But go one step
>further.
>
>Select unique environment variables (perhaps: $PERLHOME,
>$PERLPATH, $PERLOPTS) test for them and use them if present to
>define the location of the binary ($PERLHOME) and if useful a
>path ($PERLPATH) to find libraries.  $PERLOPTS can be used to
>pass the equivalent of command line options.

I hate having a zillion environment variables laying around.

I hate man(1) not knowing where the man page got stashed.

I hate auxilliary files laying around in .../lib.

I hate telling people how to setup and/or find the above mentioned
stuff.

I've been tossing around the idea of using the comment sections
of COFF object files (sorry BSD) to store auxilliary files, manual
pages, and the like.  Then, all you need is the PATH variable set
correctly.  A build of a program which had an auxilliary file (prog.aux)
and a man page (prog.1) would look like this:

	cc prog.c -o prog
	coff_comm -a "ManPage1" prog.1 prog	# Add comment section
	coff_comm -a "prog.aux" prog.aux prog	# Add comment section

To get the man page:

	coff_comm -x "ManPage1" prog | man	# Extract comment section

(Of course, suitably disguised for mortals as a shell script).

The whole COFF comment package would consist of the aforementioned
coff_comm program, plus a library which (hopefully) would allow
position independence whether the needed auxilliary files are stashed
inside the COFF file, or whether they are laying around somewhere
else.

I have a prototype of this scheme already.  I wonder if there's
any net-wide interest?
-- 
		Rick Richardson, President, PC Research, Inc.

(201) 542-3734 (voice, nights)   OR     (201) 834-1378 (voice, days)
uunet!pcrat!rick (UUCP)			rick%pcrat.uucp@uunet.uu.net (INTERNET)

dudek@ubglue.ksr.com (Glen Dudek) (02/24/88)

In article <473@pcrat.UUCP> rick@pcrat.UUCP (Rick Richardson) writes:
>
>I hate having a zillion environment variables laying around.
>
>I hate man(1) not knowing where the man page got stashed.
>
>I hate auxilliary files laying around in .../lib.
>
>I hate telling people how to setup and/or find the above mentioned
>stuff.
>

The best software distribution scheme I have seen uses command line
arguments to pass information about where the auxiliary files for
a program reside.  This is taken from the startup of the Saber-C
program development environment (a wonderful debugging and program
development system :-)

#!/bin/sh
exec /usr/local/lib/Saber/saber_exec -h/usr/local/lib/Saber \
    -gsaber@harvard.harvard.edu $*

This requires no changes to object file format, no environment variables
that need to be put in everyones login initialization, no recompiling
after changing a configuration file, and is completely self-documenting.

Unfortunately, it doesn't help the man page problem.
--
Glen Dudek
Kendall Square Research
Disclaimer: These are my opinions, and may not be anyone elses.