From: lwall@netlabs.com (Larry Wall)
Newsgroups: comp.lang.perl
Subject: Re: explanation of the camel book code needed
Keywords: sh csh perl ksh running with shells
Date: 6 Nov 92 23:26:09 GMT
Organization: NetLabs, Inc.

The code in question is something like

    eval '(exit $?0)' && eval 'exec /usr/bin/perl -S $0 ${1+"$@"}'
    & eval 'exec /usr/bin/perl -S $0 $argv:q'
	if 0;

The interpretation by sh:

    '(exit $?0)' is a single-quoted string, and is passed to eval unchanged.
    eval processes the string:
	() forks a subshell and executes the command inside.
	$? returns 0 because there was no last command to return status from.
	$?0 interpolates to 00.
	exit 00 exits the subshell with a 0 status, setting $? in our shell.
    && evaluates the $? set by the left side, and since it's 0, evaluates
      the right side.
    'exec /usr/bin/perl -S $0 ${1+"$@"}' is a single-quoted string, and is
      passed to eval unchanged.
    eval processes the string:
	$0 is interpolated to be the current script name.  On some systems
	  this will be a fully qualified pathname, and on others it'll be
	  just the filename.
	$1 is evaluated, and if set, "$@" is interpolated, passing all the
	  passing all the arguments into the perl command.  If not set,
	  nothing is interpolated.  (This is a workaround for an sh bug,
	  in which "$@" interpolates an unwanted "" if there are no arguments.
	  We use "$@" rather than $* because $* doesn't properly quote
	  filenames containing spaces and such.)
	/usr/bin/perl is executed.  The -S tells perl to look for $0 in
	  the path if $0 isn't a fully qualified pathname.
    The last two lines remain unevaluated because we did an exec.
    
The interpretation by csh:

    '(exit $?0)' is a single-quoted string, and is passed to eval unchanged.
    eval processes the string:
	() forks a subshell and executes the command inside.
	$?0 interpolates 1 because the $0 variable is set.
	exit 1 exits the subshell with a 1 status, setting $status in our shell.
    && evaluates the $status set by the left side, and since it's 1, does NOT
      evaluate the right side, but procedes to the next statement.
    The & on the next line is ignored because there's a null command before it.
    'exec /usr/bin/perl -S $0 $argv:q' is a single-quoted string, and is
      passed to eval unchanged.
    eval processes the string:
	$0 is interpolated to be the current script name.
	$argv:q is interpolated to be the current arguments, with a modifier
	  that says to pretend they were all quoted.
	/usr/bin/perl is executed.  The -S tells perl to look for $0 in
	  the path if $0 isn't a fully qualified pathname.
    The last line remains unevaluated because we did an exec.

The interpretation by perl:

    The entire program is parsed first, so all three lines are parsed as
      one expression statement with a modifier.  The first two lines are the
      expression.  We now see that the & on the second line is there merely
      to tie the two lines together into a single Perl expression--it wouldn't
      matter what it is as long as csh ignores it.
    The Perl program is executed.  The statement modifier is false, so
      the entire statement is skipped.  It doesn't matter at all to Perl
      what the syntax of the expression in the first two lines is, as
      long as it comes out to a single expression.

The main clinker in this is that there are Certain Vendors who have
been peddling, since time immemorial, a brain-dead version of csh
(I ask myself, was there ever a brain-live version of csh?) that
reverses the meanings of && and ||.  On *some* of these machines, you
can prefix the above with a line that reads

    "true" || eval 'exec /usr/bin/perl -S $0 $argv:q';

Unfortunately, some systems are so far gone that their csh doesn't
even have an eval.  In such cases, immediate and radical amputation of
the power cord is the only recourse.

Larry
Newsgroups: comp.lang.perl