Forum: Ruby using shebang with rvm?

Posted by Wesley Rishel (wrishel)
on 2012-12-27 05:53
What would be the appropriate path to use after a shebang in the first
line of a ruby source, if I want to use the currently active rvm
version of Ruby?

I am currently using rvm 1.17.3

I hope it doesn't matter, but just in case I am on Mountain Lion.
Posted by D. Deryl Downey (ddd)
on 2012-12-27 06:29
(Received via mailing list)
Its no different with RVM than without. RVM is just a set of scripts 
that downloads, compiles and installs various rubies for you. It also 
makes gem sets as well. The gem sets are just symlinked directories. RVM 
then sets the GEM_HOME, RUBY_HOME, and various shell variables that Ruby 
normally reads.

This means that once you install Ruby via RVM and tell it which one you 
want to use, it sets the vars and its done. After that its all Ruby 
itself. So, to answer your question, you would use #!/usr/bin/env as the 
first line.


D. Deryl Downey

"The bug which you would fright me with I seek" - William Shakespeare - 
The Winter's Tale, Act III, Scene II - A court of Justice.
Posted by Hans Mackowiak (hanmac)
on 2012-12-27 06:34
he means
#!/usr/bin/env ruby
Posted by D. Deryl Downey (ddd)
on 2012-12-27 06:43
(Received via mailing list)
Correct. My apologies.


#!/usr/bin/env ruby


--
D. Deryl Downey

"The bug which you would fright me with I seek" - William Shakespeare - 
The Winter's Tale, Act III, Scene II - A court of Justice.
Posted by Wesley Rishel (wrishel)
on 2012-12-27 07:23
Thanks, but most shebang files I have seen include an absolute path to
the language interpreter. Rvm does not intervene when the shell is
interpreting a script containing a shebang. So, for example, if you
create this script on OS 10.8 it returns 1.8.7 no matter what version
you have selected in rvm.

$ cat tryshbang.rb
#! /usr/bin/ruby
puts RUBY_VERSION
$ ./tryshbang.rb
1.8.7
$

I have since found the following recommendation in the Wikipedia article
on shebang: http://en.wikipedia.org/wiki/Shebang_(Unix)

#! /usr/bin/env ruby
puts RUBY_VERSION

It works.
Posted by D. Deryl Downey (ddd)
on 2012-12-27 07:30
(Received via mailing list)
Of course, because you use a FULL path. By not using #!/usr/bin/env ruby 
(notice the /usr/bin/env part) you're specifically calling a specific 
ruby which bypasses ALL environment variables and uses the direct 
binary. No one told you to use #!/usr/bin/ruby. They said #!/usr/bin/env 
ruby  which tells the script to query the path for the first ruby found 
and use its environment vars, and to make its exit code status be the 
return value of the script itself, when its done executing. (See man 
env)


--
D. Deryl Downey

"The bug which you would fright me with I seek" - William Shakespeare - 
The Winter's Tale, Act III, Scene II - A court of Justice.
Posted by D. Deryl Downey (ddd)
on 2012-12-27 07:37
(Received via mailing list)
This is the difference.

https://gist.github.com/4386008


--
D. Deryl Downey

"The bug which you would fright me with I seek" - William Shakespeare - 
The Winter's Tale, Act III, Scene II - A court of Justice.
Posted by Stu (Guest)
on 2013-01-02 00:32
(Received via mailing list)
It's primarily for portability. Using env more or less defeats
portability issues as every box could have ruby installed somewhere
else. For example rvm really is just a environment hack.

When you call a program, in this case ruby, with env your shell will
locate the first ruby it finds in the path. This is just a hashed
lookup table for speed. Basically when you call for example % ruby
program.rb it expands to (say on my system) % /usr/local/bin/ruby
/path/to/my/program.rb -- of course rvm takes precedence over the
system paths as that's what the utility was designed to do.

A common mistake, which your observing, is where a direct path is
used; the programmer does not take into account that different
operating systems put their binaries in different directories.

Always use env. Any of the absolute paths which you see are usually
from uninformed dilettantes or users whom want world domination for
their tools or OSes and are throwing a fit by forcing any of their
users to write a small sed script to patch their install.

If you would like to see your paths hash you can simply type in the
command hash at the prompt. If you need to update your hash you can
use the -r option. If you would like to know more, outside of the web
wiki, read the ash (not bash) man page: http://man.freebsd.org/sh

Quote:
     hash [-rv] [command ...]
             The shell maintains a hash table which remembers the 
locations of
             commands.  With no arguments whatsoever, the hash command 
prints
             out the contents of this table.  Entries which have not 
been
             looked at since the last cd command are marked with an 
asterisk;
             it is possible for these entries to be invalid.

             With arguments, the hash command removes each specified 
command
             from the hash table (unless they are functions) and then 
locates
             it.  With the -v option, hash prints the locations of the 
com-
             mands as it finds them.  The -r option causes the hash 
command to
             delete all the entries in the hash table except for 
functions.

~Stu
Posted by Wesley Rishel (wrishel)
on 2013-01-02 04:43
Stu wrote in post #1090776:
> It's primarily for portability. Using env more or less defeats
> portability issues as every box could have ruby installed somewhere
> else.
>
> ...

Thanks, Stu, the entire note was very helpful.

I am not sure if you are suggesting that I should also be able to have a
non-absolute path to env command.

Using bash on OS 10.8 I find that a she-bang for Ruby just doesn't work
unless it points to some absolute path.

The most portable I can make a file is to say

         #! /usr/bin/env ruby

Anyway, that approach meets my needs.

Regards,

Wes 

____

"With consistency a great soul has simply nothing to do. Speak what you
think today in hard words and tomorrow speak what tomorrow thinks in
hard words again, though it contradict everything you said today. "

                           Ralph Waldo Emerson

____
 
Posted by Stu (Guest)
on 2013-01-02 09:01
(Received via mailing list)
Wes ~

That is what I was saying. Also this is correct if you deviate from
any posix syntax or use a third party language. So env would also be
used for bash or zsh where bashisms( i.e. shell extension) are used
but not ash.

example to use bash it's the same semantically for portability if one
requires bash or zsh specific syntax:

#!/usr/bin/env ksh
#!/usr/bin/env bash
#!/usr/bin/env zsh
#!/usr/bin/env fish


All bourne derived shells( i.e. not csh) are backward compatible with
posix sh which is a small mixture of original bourne syntax and korn
syntax.

The only time you would ever want to use a direct path is with a posix
sh script as so:

#!/bin/sh

or csh ... but don't use csh =)

#!/bin/csh -f

If your really curious on the spec you can be read here:
http://rubyprogrammer.net/~stu/posix/

You can set your path inside your interactive rc file with the $PATH
variable. It's delimited with a colon and is a first positive match
wins hash. If your writing a script that depends on knowing where your
binaries are you can use a variable to hold the direct path to the
executable or set the path variable directly inside the script.

Trivial example of embedded ruby embedded inside shell:

#!/bin/sh
r=/path/to/mri/ruby20
$r <<EOF
puts "Hello, world!"
RbConfig::CONFIG.each_pair { |k,v| puts k+':<=>:'+v }
s=RbConfig::CONFIG.values.grep /bin\/*sh/
puts <<EOR
Bye bye your current shell is #{s}
Your ruby is ${r}
EOR
EOF

Set the execute bit and run it through a pipe to less or tail -2 for
example. Have another ruby. Wanna glue one to the other? Create
benchmark results? Just some ideas. Maybe not the most practical
examples but provide you some insight on what may be useful with a
couple lines of shell code.

Bash is an okay shell for beginners. Consider zsh for interactive use
as it has a nice flow to development once you begin to customize it. I
have ash on FreeBSD which is very fast for shell scripts as it's <70kb
binary in contrast to bash being over a meg. I don't believe they
ported Almquist's shell to OSX. Maybe homebrew has it (sometimes under
the name dash in the gnu distros so I'm unsure what got ported on osx
as it's a mashup of FreeBSD kernel with BSD, next and gnu userland)...

My main toolset preference tends to be sh for system level automata,
primarily because that is my background... consider scripting a
network where ruby may or may not be present machine to machine , ruby
for larger stack oriented projects where oops, arrays may be needed,
zsh, vi, irb for my preferred development stack.

I also use rvm which is one of the few bash specific scripts, actually
I would call rvm a framework utility at this point, which it is obvious 
where
posix was considered but the need for the automation on directory
switching with rvmrc for developers whom needed various sandboxing
with minimal setup usurped avoiding the extended syntax of bash. The
need for arrays also is where bash becomes the dependency.

Take a look at Wayne's code. You will see some of the best shell code
by someone who takes such things seriously by studying rvm.

Other projects of the same vein such as chruby or rbenv make no effort
for portability outside of forcing user to install bash or run a
computer only capable of supporting homebrew .

I do find it ironic how the author of rbenv promoted it initially with
sort of a dunning kruger style marketing his way was the "one true
way" when it's far from a minimalist's alternative to rvm while
deviating from posix for no reason other than it's obvious the rbenv
developer is not a system administrator and knows of nothing other
than how to provide FUD with ad hominem bullet points like his lamers
statement that rvm is dangerous and error-prone. I guess this sort of
thing is how people get themselves noticed when either vying for some
corporate employment contract or simply to gain some sort of
superficial notoriety.

On a simpler level consider command env to work like how you
understand how the ruby interpreter yields results from it's block
iterators. /usr/bin/env ruby basically has ruby as an argument to the
command env which locates ruby in the path hash and yields the result
which in this case is the path located to the shell which instructs
the kernel to create a memory overlay to load ruby after env evaluates
the ruby location; From there ruby will be executed in place in order
to evaluate any of the code after which in turn yields each token to
the executable. The env will work with any command hashed from the
$PATH global environment variable.

Happy Hacking.

~Stu
Please log in before posting. Registration is free and takes only a minute.
Existing account (Switch to SSL-encrypted connection)
NEW: Do you have a Google/GoogleMail or Yahoo account? No registration required!
Log in with Google account | Log in with Yahoo account
No account? Register here.