Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

proper usr/bin/env ruby shebang

125 views
Skip to first unread message

Rob Sanheim

unread,
Jan 31, 2007, 11:45:15 AM1/31/07
to
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...

This works fine from the command line:

rsanheim@seekingalpha06a [/sa/bin]$ /usr/bin/env ruby -w
FOO = "hi"
FOO = "bye"
-:2: warning: already initialized constant FOO

Any ideas? Forgive me if I'm missing something obvious here...This is
red hat 4, I believe...

thanks,
Rob

pat eyler

unread,
Jan 31, 2007, 11:56:03 AM1/31/07
to

Either you're dating yourself, or you mean RHEL 4 ... (I still have
manuals from both RHL 3 and 4 (and maybe install media if I look
hard enough))


>
> thanks,
> Rob
>
>


--
thanks,
-pate
-------------------------
http://on-ruby.blogspot.com

Rob Sanheim

unread,
Jan 31, 2007, 11:59:24 AM1/31/07
to

You're right, I meant RHEL4.
- rob

ara.t....@noaa.gov

unread,
Jan 31, 2007, 12:09:57 PM1/31/07
to

harp:~ > cat a.rb
#!/usr/bin/env ruby -w
p $VERBOSE
FOO = 42 and FOO = 42

harp:~ > ruby a.rb
true
a.rb:3: warning: already initialized constant FOO

harp:~ > ruby -v
ruby 1.8.4 (2005-12-01) [i686-linux]

harp:~ > uname -srm
Linux 2.4.21-47.0.1.EL i686

harp:~ > cat /etc/redhat-release
Red Hat Enterprise Linux WS release 3 (Taroon Update 8)


what happens for you?

-a
--
we can deny everything, except that we have the possibility of being better.
simply reflect on that.
- the dalai lama

Nobuyoshi Nakada

unread,
Jan 31, 2007, 12:12:53 PM1/31/07
to
Hi,

At Thu, 1 Feb 2007 01:45:15 +0900,
Rob Sanheim wrote in [ruby-talk:237036]:


> 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

Do not rely on /usr/bin/env, it may not exist.

#!/bin/sh
exec ruby -x "$0" "$@"
#!ruby -w

--
Nobu Nakada

Rob Sanheim

unread,
Jan 31, 2007, 12:17:57 PM1/31/07
to
On 1/31/07, ara.t....@noaa.gov <ara.t....@noaa.gov> wrote:
> harp:~ > cat a.rb
> #!/usr/bin/env ruby -w
> p $VERBOSE
> FOO = 42 and FOO = 42
>
> harp:~ > ruby a.rb
> true
> a.rb:3: warning: already initialized constant FOO
>
> harp:~ > ruby -v
> ruby 1.8.4 (2005-12-01) [i686-linux]
>
> harp:~ > uname -srm
> Linux 2.4.21-47.0.1.EL i686
>
> harp:~ > cat /etc/redhat-release
> Red Hat Enterprise Linux WS release 3 (Taroon Update 8)
>
>
> what happens for you?
>
> -a
> --

Hmm, so that works -- the issue is where I run it as an executable
(see the end of the log)

sa [~]$ ruby a.rb


true
a.rb:3: warning: already initialized constant FOO

sa [~]$ ruby -v
ruby 1.8.5 (2006-12-25 patchlevel 12) [i386-linux]

sa [~]$ uname -srm
Linux 2.6.9-42.0.3.ELsmp i686

sa [~]$ cat /etc/redhat-release
Red Hat Enterprise Linux ES release 4 (Nahant Update 4)

sa [~]$ chmod +x a.rb

sa [~]$ ./a.rb
/usr/bin/env: ruby -w: Permission denied

- Rob

Rob Sanheim

unread,
Jan 31, 2007, 12:20:38 PM1/31/07
to

Ugh, so I need that at the top of all these scripts? I thought
/usr/bin/env was the 'better' way to go?

ara.t....@noaa.gov

unread,
Jan 31, 2007, 12:25:42 PM1/31/07
to
On Thu, 1 Feb 2007, Rob Sanheim wrote:

you can use

#! /usr/bin/env ruby
$VERBOSE=true

Kalman Noel

unread,
Jan 31, 2007, 12:24:30 PM1/31/07
to
ara.t.howard:

> harp:~ > cat a.rb
> #!/usr/bin/env ruby -w
> p $VERBOSE
> FOO = 42 and FOO = 42
>
> harp:~ > ruby a.rb
> true
> a.rb:3: warning: already initialized constant FOO

There's no shell or anything here interpreting the shebang.

Kalman

Rob Sanheim

unread,
Jan 31, 2007, 12:50:15 PM1/31/07
to
> On Thu, 1 Feb 2007, Rob Sanheim wrote:
>
> > On 1/31/07, Nobuyoshi Nakada <no...@ruby-lang.org> wrote:
> >> Hi,
> >>
> >> At Thu, 1 Feb 2007 01:45:15 +0900,
> >> Rob Sanheim wrote in [ruby-talk:237036]:
> >> > 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
> >>
> >> Do not rely on /usr/bin/env, it may not exist.
> >>
> >> #!/bin/sh
> >> exec ruby -x "$0" "$@"
> >> #!ruby -w
> >>
> >
> > Ugh, so I need that at the top of all these scripts? I thought
> > /usr/bin/env was the 'better' way to go?
> >
>
> you can use
>
> #! /usr/bin/env ruby
> $VERBOSE=true

That will work - thanks.

Rob Sanheim

unread,
Jan 31, 2007, 2:06:37 PM1/31/07
to
On 1/31/07, Rob Sanheim <rsan...@gmail.com> wrote:

My hosting provider provided this very helpful post on this whole mess:

http://elliotth.blogspot.com/2006/04/lesson-about-using-env1-in-script.html

Which explains why passing in -w wasn't working, and why just setting
$VERBOSE to true isn't the same thing. Seems like it shouldn't be
this hard to get a cross platform script working, with warnings.

- Rob

Eric Hodel

unread,
Jan 31, 2007, 2:09:34 PM1/31/07
to
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.

Paul Brannan

unread,
Jan 31, 2007, 2:53:40 PM1/31/07
to
On Thu, Feb 01, 2007 at 02:20:38AM +0900, Rob Sanheim wrote:
> Ugh, so I need that at the top of all these scripts? I thought
> /usr/bin/env was the 'better' way to go?

This issue has come up before (see [ruby-talk:27508]). However, Austin
Ziegler pointed out in [ruby-talk:56340] that the sh/exec solution won't
work on non-Unix environments. See also 'perldoc perlrun' for more
discussion on the issue (ruby takes much of its behavior from perl in
this case).

Paul


gga

unread,
Jan 31, 2007, 6:33:51 PM1/31/07
to

All solutions posted so far are broken in one way or another.

What will work across platforms and OSes is this:

#! /usr/bin/env ruby

And add:

export RUBYOPT="-w $RUBYOPT"

to your environment (.bashrc) or:

setenv RUBYOPT "-w $RUBYOPT"

for cshrc, tcsh (.cshrc, .tcshrc, etc). For windows, do:

set RUBYOPT="-w %RUBYOPT%"

in a bat file (or in your environment variables for the user or the
machine).
The additional benefit of this is that you will not only get your
little script compiled with warnings on, but every piece of ruby code
you run, too.
Also, if you need performance, you can easily turn off the -w flag,
without having to modify a single file.

Mike Kasick

unread,
Feb 1, 2007, 12:02:52 AM2/1/07
to
On Thu, Feb 01, 2007 at 01:45:15AM +0900, Rob Sanheim wrote:

> Any ideas?

I tend to do:

#!/usr/bin/env ruby
BEGIN {$VERBOSE = true}

as I think that's the best you can do within a single script. If the
link referenced in another reply is correct, then warnings won't be
emitted as the script initially loads. However, doing a manual "ruby -w
foo_script.rb" once to test the code should catch any of these warnings.

Paul Brannan

unread,
Feb 1, 2007, 10:21:25 AM2/1/07
to
On Thu, Feb 01, 2007 at 08:35:08AM +0900, gga wrote:
> What will work across platforms and OSes is this:
>
> #! /usr/bin/env ruby

This will not work for platforms that put env in /bin or don't have /usr
mounted.

Paul


Will Parsons

unread,
Feb 1, 2007, 5:22:44 PM2/1/07
to
Some platforms don't even have an env. I regularly work on one.

- Will

Garance A Drosehn

unread,
Feb 1, 2007, 5:23:49 PM2/1/07
to

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 = dro...@gmail.com
Senior Systems Programmer
Rensselaer Polytechnic Institute; Troy, NY; USA

ara.t....@noaa.gov

unread,
Feb 1, 2007, 5:27:14 PM2/1/07
to
On Fri, 2 Feb 2007, Garance A Drosehn wrote:

> #!/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.

thanks garance! i'm filing this under 'definitive' in my mail ;-)

Garance A Drosehn

unread,
Feb 1, 2007, 5:51:34 PM2/1/07
to

Well, on many of my systems, if /usr is not mounted, then 'ruby' itself
is also not available! :-)

I have a bigger concern with using /usr/bin/env for this. The
/usr/bin/env trick will only work if ruby *IS* in the PATH of the
person who is running the ruby script, and if that version of ruby is
the version expected by the script. On many systems that is a safe
assumption, but it isn't always true.

Consider something like MacOS 10, for instance, where Apple
ships one version of ruby in /usr/bin, but many people will install a
newer version in /opt/local/bin. I've had some scripts fail because
the user running them didn't have /opt/local/bin in their PATH.

(ie, I helped them install ruby into /opt/local/bin using macports,
but they didn't update their settings for PATH)

gga

unread,
Feb 1, 2007, 11:05:27 PM2/1/07
to
On 1 feb, 19:51, "Garance A Drosehn" <dros...@gmail.com> wrote:

> On 2/1/07, Paul Brannan <pbran...@atdesk.com> wrote:
>
> > On Thu, Feb 01, 2007 at 08:35:08AM +0900, gga wrote:
> > > What will work across platforms and OSes is this:
>
> > > #! /usr/bin/env ruby
>
> > This will not work for platforms that put env in /bin or don't have /usr
> > mounted.
>
> Well, on many of my systems, if /usr is not mounted, then 'ruby' itself
> is also not available! :-)
>
> I have a bigger concern with using /usr/bin/env for this. The
> /usr/bin/env trick will only work if ruby *IS* in the PATH of the
> person who is running the ruby script, and if that version of ruby is
> the version expected by the script. On many systems that is a safe
> assumption, but it isn't always true.

It should be.

>
> Consider something like MacOS 10, for instance, where Apple
> ships one version of ruby in /usr/bin, but many people will install a
> newer version in /opt/local/bin. I've had some scripts fail because
> the user running them didn't have /opt/local/bin in their PATH.
>

More the reason to use /usr/bin/env. That way, you are not hard-
coding the script to a specific version of ruby.
If you had done the opposite and had used #! /usr/bin/ruby (or
whatever location macs put ruby by default ), your users would have
never been able to use a different version of ruby without having to
manually change the path to ruby in all scripts or type "ruby" itself.
If your users have path issues, your likely problem is not /usr/bin/
env but a bad system-wide .bashrc or .tcshrc configuration file that
is not adding the path automatically (a sysadmin issue) or some lack
of knowledge on the user's part who probably overrode what the
sysadmin did by setting path improperly. If it is a sysadmin issue,
talk to your sysadmin (and probably, start shopping for a new
sysadmin :). If it is a user issue, as it is more likely, teach him
how to change variables without overriding system-wide configurations
(ie. PATH=stuff:$PATH instead of just PATH=stuff).
Another way this happens is when a user wants to use an unpopular (or
an incompatible) shell within the company (say, zsh in a place where
tcsh is the default) and as such he does not inherit the settings the
sysadmin sets up for him. A good way around this (I have found over
the years) is to eventually handle all environment path changes with a
custom script (usually written in perl or ruby) rather than by using
the shell's built-in commands (setenv/export/etc). The ruby script is
the one in charge of detecting the shell the user is using and spits
out the correct setenv commands for it (this output is evaled thru an
alias).
See for example (this only handle output for a single shell, thou):
http://seriss.com/people/erco/unixtools/ (epath)
or if you want ruby code:
http://www.highend3d.com/downloads/tools/os_utils/epath-3183.html
http://rubyforge.org/projects/ggenv/ ( a simpler library )

gga

unread,
Feb 1, 2007, 11:16:53 PM2/1/07
to

env in bin is definitively non-standard unix, so that platform is
likely to end with a sudo ln -s /bin/env /usr/bin almost immediately.
I was not aware of any unix platform without env. What platform are
you on btw? Obviously windows does not have env, but you solve issues
there with file associations or by using some unix environment (like
cygwin, etc).

Daniel DeLorme

unread,
Feb 2, 2007, 10:25:21 PM2/2/07
to
Nobuyoshi Nakada wrote:
> Do not rely on /usr/bin/env, it may not exist.

Also, /usr/bin/env relies on the $PATH env variable,
so if you try to run this as a cron job it will fail
because $PATH is not set.

Daniel

gga

unread,
Feb 3, 2007, 2:40:49 AM2/3/07
to

Again, that's probably bad sysadmin or user error in setting up cron.

> grep PATH /etc/crontab
PATH=/usr/local/sbin:/usr/local/bin:/sbin:/bin:/usr/sbin:/usr/bin

If you run your own cron jobs as a normal user, you should create your
own similar crontab file. You can do so with:

> crontab /etc/crontab
> crontab -e # to edit it

(Depending on your linux flavor, your user cron file will be stored
in /var/spool/cron/crontabs/<user> (Unix/Slackware/*BSD),
/var/spool/cron/<user> (RedHat) or /var/cron/tabs/<user> (SuSE).


0 new messages