shebang for multiple versions - ruby

In my large collection of Ruby scripts, I do start my scripts with the common shebang:
#!/usr/bin/env ruby
Now I am finding some scripts that do need certain Ruby version, and no, they are no Rails apps that can be deployed under a specific Ruby version. They are just single file scripts that can be launched from the command line and fail to work with the system version.
Is there any way to write a shebang that sets the environment with rbenv/rvm before running the following code of the file?

You don't necessarily need to set up any environment. All you need is the path to the ruby binary you want to run and everything else will follow.
Here's an example on how you could set it up:
Create a folder ~/bin. This will hold pointers (symlinks) to all your personal ruby binaries.
Update your shell PATH so that ~/bin is included in the search path for executables.
Symlink any ruby binary you need in your ~/bin to the actual ruby binary.
For example in my ~/bin I have:
ruby18 -> /opt/ruby18/bin/ruby
ruby19 -> /opt/ruby19/bin/ruby
ruby20 -> /opt/ruby20/bin/ruby
Now let's say you have a script which needs 1.9 to run. Then all you need to do is:
#!/usr/bin/env ruby19
This will work if you have installed your gems into the default gem directory for each ruby executable. If you have installed gems somewhere else then it gets more complicated and you would need to modify GEM_PATH before you run your script.
If you don't want to get fancy with ~/bin then just hardcode your shebang line instead to point directly to the ruby binary:
#!/opt/ruby19/bin/ruby
...or the equivalent rbenv/rvm path.
Having symlinks in your ~/bin though will allow you to more easily update your bin pointers if let's say you compile a new patch of ruby 1.9, and you want to place it in another folder like /opt/ruby19-p123. Then you just need to update the symlink in ~/bin and all your scripts will run the new patched version.

rbenv will look for the .ruby-version file set by (for example)
$ rbenv local 1.9.3-p448
Create a simple file, check
#!/usr/bin/env ruby
puts RUBY_VERSION
Make it executable
$ chmod +x check
Run it
$ ./check
Output
1.9.3
That said, this is not a per-file setting. If there's a way to alter rbenv's behavior using the shebang, that would probably be a better fit.

Related

Why is this ruby script echoing the path to the executable?

Here's a Ruby file at /path/to/test/test.rb:
# /path/to/test/test.rb
puts 'foobar'
Here's what happens when I run it:
$ cd /path/to/test/
$ ruby test.rb
foobar
So far, so good. But:
$ cd ..
$ ruby test/test.rb
/path/to/test/ # <=== wtf?
foobar
Why does Ruby print the path to the script when I run it outside the current folder? The problem occurs only with Ruby scripts, and occurs whether or not I run it with $ ruby test.rb or make it executable with a shebang.
This is definitely nonstandard behavior caused by something in my Ruby environment, but I can't imagine what it is. I have Rails and a number of other gems installed. Any idea what might cause this?
I believe this is due to CDPATH being set in your environment. rbenv cd's while shimming Ruby and when resolving the relative path to the script file, and this causes some paths to be echoed to the terminal. In the past I've had some luck working around this issue by not exporting CDPATH in my .bash_profile (i.e. just setting it, without the export keyword), but it seems that this is not sufficient in all cases. In fact, in the current master branch tip of rbenv (which has not yet been released), they unset CDPATH at the top of the file, so it seems as though they're aware of this problem and hope to address it in the next release.
If you want this fix today, instead of waiting for the next release, you can obtain it by uninstalling rbenv through Brew (brew uninstall rbenv), and reinstalling it through Git. You will first need to rename your current ~/.rbenv directory (e.g. mv ~/.rbenv ~/.rbenv.bak), and after reinstalling rbenv, you may want to migrate your installed rubies and gems (instead of reinstalling them):
mkdir -p ~/.rbenv/versions
mv ~/.rbenv.bak/versions/* ~/.rbenv/versions/
Hope this helps!

Ruby script: shebang with absolute path to ruby not working

I am using Mac OS X. I have two versions (2.1.5 and 2.0.0) of Ruby installed. The former installed at /another/.path/to/ruby (there is a dot before "path" to mimic the fact that the path contains a dot-headed directory in between), in addition to the default system one (version 2.0.0) at /usr/bin/ruby. I used rbenv to install Ruby.
After I manually set the PATH environment variable so the default ruby command will be found in another directory: /another/.path/to/ruby. Now I check
which -a ruby
It is using correct ruby first, as output.
/another/.path/to/ruby
/usr/bin/ruby
Now I create a script, rbs, with the first line of shebang specifying the ruby to use.
#!/usr/bin/env ruby
puts 'hey there'
Then I run
./rbs
it outputs 'hey there'. Good. Meanwhile, the Ruby is using the correct version.
/usr/bin/env ruby --version
as well as
ruby --version
both output 2.1.5. So it does great job to use the new version.
However, here is where the problem occurs: now I update rbs file to be:
#!/another/.path/to/ruby
puts 'hey there'
Note that I updated the shebang to use the absolute path to the desired ruby. then I run
./rbs
It outputs:
./rbs: line 2: puts: command not found
which is too weird;
but if I run
ruby ./rbs
it outputs 'hey there' as normal. It looks like the shebang works perfect using /usr/bin/env ruby, but not for absolute path for the newly install ruby?
Why is this? Is there a way to fix it so the updated script can still work by typing the following?
./rbs
Thanks!
The puts: command not found message indicates that your script is not being run by Ruby, but by the shell instead. So first, I would double-check your shebang line's syntax and path.
Second, note that rbenv uses shims that dynamically find and run the right version of ruby (and associated programs like gem, etc). But the shims are scripts, and scripts can't themselves be shebang interpreters; you have to find and use the actual path to the ruby executable (as output by rbenv which ruby).
On the other hand, since /usr/bin/env is an executable, you can always use something like #!/usr/bin/env ruby, which will work even if the ruby it finds in the path is itself a script.
I can't comment, (otherwise I'd add as a comment) but I think its worthwhile to add that the
#!/usr/bin/env ruby
MUST be the first line of the file. This tripped me up for a while.
source

Ruby 1.9.3 #OSX Lion and Cron

I installed Ruby 1.9.3p125 via this guide (up to point #5): LINK
Now I have this problem: my script works wonderfully from my command line, but if I execute it from Cron it seems to use a default environment and defaults to /usr/bin/ruby instead of mine (~/.rvm/rubies/ruby-1.9.3-p125/bin/ruby). What is the best way to have executed commands - manually or via cron - produce the same results?
PS: It seems to skip processing ~/.bash_login for example, where rvm is loaded into PATH
In your crontab line, you can source the .bash_login before you script is run.
source ~/.bash_login && <your original command here>
That way your script will have everything you have when you run it.
The usual way recommended to do this would be to put the full path to the executable in your crontab. E.g.
crontab should show:
/Users/Poochie/.rvm/rubies/ruby-1.9.3-p125/bin/ruby /full/path/to/script.rb
or whatever the full path is. It's much more robust than trying to get rvm loading, as here an rvm script is modifying your path for you. If you want to set it to whichever is the rvm default ruby (e.g. whatever was set by rvm use x.x.x --default), You can use: /Users/Poochie/.rvm/bin/ruby as the executable instead, e.g.:
/Users/Poochie/.rvm/bin/ruby /full/path/to/script.rb
I actually found this post which helped me a lot: LINK
I managed to run my script as I wanted but the questions is theoretically still open because the issue could still affect cron usage in general.

Run Ruby script without invoking it directly

I'm looking for solution how can run Ruby script without invoking it directly like
ruby /path/to/file.rb
So far, I have been using aliases in my .bashrc to create shortcut like
alias myscript='ruby /path/to/file.rb'
But now, I need to create a gem which I'd like to use on different computers and my current approach doesn't fit well for this.
What you could do is the following:
Create a shell script which invokes the Ruby script as your alias does:
ruby /path/to/file.rb
Set a softlink to the /usr/bin/ path to invoke it in the shell using somecommand:
ln -s /full/path/to/the/previously/created/shellscript /usr/bin/somecommand
If you wanna go further, you could create a shell script which does the soft-linking automatically.
Add a shebang to the beginning of the script
#!/usr/bin/env ruby
(check that shebang is #!)
then make your script executable
chmod +x file.rb
Now you can run the file as a "standalone" executable
# For example
$ ./file.rb
("Standalone", because the ruby interpreter still needs to be installed somewhere in your path.)

Launching Ruby without the prefix "Ruby"

I'm on OS X (with bash) and a newbie at unix. I want to know if it's possible to amend some file such that to run a ruby program, I don't need "ruby file.rb", but instead can just run "ruby.rb".
Is there a reason NOT to do this?
Thanks!
Yes you can do this.
Assuming ruby.rb has something like this in it:
#!/usr/bin/env ruby
puts 'Hello world'
At the command line: chmod +x ruby.rb
This makes it executable.
Then you can execute it like this:
./ruby.rb
For more details see wikibooks.
EDIT (Jörg W Mittag): Using #!/usr/bin/env ruby instead of #!/usr/bin/ruby as the shebang line is more portable, because on every Unix produced in the last 20 years, the env command is known to live in /usr/bin, whereas Ruby installations are typically all over the place. (E.g., mine lives in /home/joerg/jruby-1.2.0/bin/ruby.)
As others have mentioned, you want to have a shebang (#!) line at the beginning, and change the permissions to executable.
I would recommend using #!/usr/bin/env ruby instead of the path to Ruby directly, since it will make your script more portable to systems that may have Ruby installed in different directories; env will search in your search path, and so it will find the same Ruby that you would execute if you ran ruby on the command line. Of course, this will have problems if env is in a different location, but it is much more common for env to be at /usr/bin/env than for Ruby to be at /usr/bin/ruby (it may be in /usr/local/bin/ruby, /opt/bin/ruby, /opt/local/bin/ruby, etc)
#!/usr/bin/env ruby
puts "Hello!"
And make it executable:
chmod +x file.rb
chmod +x /path/to/file
No reason not to do it, as long as you prefix the interpreter with a shebang (#!/usr/local/ruby or whatever the path is on OSX). The shell doesn't care.
Place the correct shebang as the first line of your file. ex:
#!/usr/bin/ruby
in the shell, make the file executable
chmod +x file
If you want to do anything more complicated with running this application, you can always create a shell script:
#! /bin/sh
ruby ruby.rb
If you save it to run_script, you just have to chmod +x it as mentioned previously, then execute the following command:
$ ./run_script
I doubt this will be any more useful in your particular situation than the solutions already mentioned, but it's worth noting for completeness's sake.

Resources