On 1/31/07, Eric Hodel <drbrain / segment7.net> wrote:
> On Jan 31, 2007, at 08:45, Rob Sanheim wrote:
> > I'm trying to convert some bash scripts to use /usr/bin/env ruby
> > instead of hardcoded shebang lines, and running into an issue.  Using
> > this:
> >
> > #!/usr/bin/env ruby -w
> >
> > results in this error:
> >
> > /usr/bin/env: ruby -w: No such file or directory
> >
> > If I remove the -w, it runs and works fine.   But of course, I want
> > the warnings check in there...
>
> Linux's env/shebang is broken, so you can't use the shebang this
> way.  It decides "ruby -w" is the name of the thing you want to
> lookup, and of course env can't find that because there isn't one.

This is not the fault of Linux.  It's an unavoidable consequence of the way
the shebang-line is defined in various standards. In fact, I'm the guy who
fixed FreeBSD to comply with those standards, and thus I deliberately
changed the way FreeBSD handled shebang lines from "convenient" to
"broken".  For reasons which might not be intuitively obvious, the broken
behavior is required.

Since FreeBSD *used* to process the shebang line in a more convenient
way, I also came up with some changes to /usr/bin/env which can be used
to recreate the more convenient problem.  However, those new options are
only available on FreeBSD (afaik).

I also have to write ruby or perl scripts which have to work on a variety of
unix-based operating systems.  What I have come up with is the following.
I'm sure that it will not work on some operating system, but it works on the
dozen operating systems that I have to care about, in all situations that I
have cared about.

#!/bin/sh
# -------+---------+---------+-------- + --------+---------+---------+---------+
#     /  This section is a safe way to find the interpretter for ruby,  \
#    |   without caring about the user's setting of PATH.  This reduces  |
#    |   the problems from ruby being installed in different places on   |
#    |   various operating systems.  A much better solution would be to  |
#    |   use  `/usr/bin/env -S-P' , but right now `-S-P' is available    |
#     \  only on FreeBSD 5, 6 & 7.                        Garance/2005  /
OSRUBYBIN=
for fname in /usr/local/bin /opt/csw/bin /opt/local/bin /usr/bin ; do
   if [ -x "$fname/ruby" ] ; then OSRUBYBIN="$fname/ruby" ; break; fi
done
if [ -z "$OSRUBYBIN" ] ; then
    echo "Unable to find a 'ruby' interpretter!"   >&2
    exit 1
fi

eval 'exec "$OSRUBYBIN" -x -S $0 ${1+"$@"}'
echo "The 'exec \"$OSRUBYBIN\" -x -S ...' failed!" >&2
exit 1
#! This #!-line starts the real script, due to the marker: ruby
....[ and then the first line of the real ruby script]...

Obviously you could add the '-w' after '-x' on the eval/exec line, if you
also wanted that option.  And if you do something weird like install
'ruby' in /bin (so that you can find out when /usr is not mounted), then
you'd need to add that to the list of directories which are searched.

In some cases, I also set a new value for PATH= in the /bin/sh
portion of the script, to avoid ruby's warning about an "Insecure
world writable dir".  That warning message can also be avoided
by setting $VERBOSE in the ruby script, but in some cases it's
just easier for me to change the value for PATH.

I suspect that all this is too esoteric for most people to other with!  :-)
It really is rather absurdly complicated to get 100% right in 100% of
the situations that every ruby script might be run in.

-- 
Garance Alistair Drosehn     =             drosihn / gmail.com
Senior Systems Programmer
Rensselaer Polytechnic Institute;             Troy, NY;  USA