Ruby script: shebang with absolute path to ruby not working - ruby

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

Related

In a Ruby gem, is it possible to have executables written in other languages?

I have a gem which has an executable in bin/. A wildcard is used in the gemspec:
s.executables = Dir["bin/*"].map &File.method(:basename)
If I have a ruby file at bin/my_file which had chmod a+x run, then it's found in the PATH in bash:
#!/usr/bin/env ruby
puts "working ruby script"
However I have another executable written in coffeescript at bin/my_file.coffee:
#!/usr/bin/env coffee
console.dir "printing from coffee file"
When I run my_file.coffee in shell, it tries to read this script with ruby instead of coffeescript.
How can I run this executable with coffeescript as intended?
As it stands, I'm using a workaround which is to wrap my coffee code as a string in my ruby app and then passing it to coffee -e and capturing the output.
Also, looking at this RubyGems issue shows the official explanation:
RubyGems is not meant to support arbitrary executables.
OK. So is there an alternative besides wrapping code in heredoc?
Is there a good reason this restriction is in place?
I guess it's simply in the specification of RubyGems:
https://github.com/zzak/rubygems/commit/709c5aae7ffd9958cc2ea89dc2caf6b7e02c56b7
+ # Executables included may only be ruby scripts, not scripts for other
+ # languages or compiled binaries.
+ #

ZSH Ruby command not found

I'm pretty inexperienced with terminal type stuff besides the most basic commands, I recently switched from Bash to ZSH with in oh-my-zsh. I'm trying to make an executable ruby script at usr/bin/test.rb. For what it's worth, I never tried this with bash so I have no idea if its zsh specific.
$~ test.rb
/usr/bin/test.rb: line 2: puts: command not found
$~ ruby test.rb
ruby: No such file or directory -- test.rb (LoadError)
and my .zshrc file:
export ZSH=$HOME/.oh-my-zsh
source $ZSH/oh-my-zsh.sh
export PATH="/Users/jason/.rvm/gems/ruby-2.0.0-p247/bin:/Users/jason/.rvm/gems/ruby- 2.0.0-p247#global/bin:/Users/jason/.rvm/rubies/ruby-2.0.0-p247/bin:/Users/jason/.rvm/bin:.git/safe/../../bin:.git/bin:/usr/local/bin:/usr/bin:/bin:/usr/sbin:/sbin:/usr/X11/bin:/Users/jason/.rvm/bin"
.
~ which ruby
/Users/jason/.rvm/rubies/ruby-2.0.0-p247/bin/ruby
test.rb
#!/usr/bin/env ruby
puts 'test!'
$~ test.rb
/usr/bin/test.rb: line 2: puts: command not found
This is probably because your script is missing an essential line, often called a "pound-bang line" or, more simply, a "bang line", which tells the operating system what program to use to execute the rest of the file. Typically, for Ruby scripts, it looks like:
#!/usr/bin/ruby
or
#!/usr/bin/env ruby
and MUST be the first line in the file. When the OS opens the file, it looks for #! and, if it sees those, launches the executable at the path given, and passes the script to it. That's basic script execution on a *nix system, and applies to sh/Bash/Perl/Python/Ruby and any number of other executable applications on a *nix system.
ruby test.rb
ruby: No such file or directory -- test.rb (LoadError)
I suspect the second failed because you weren't in the /usr/bin/ directory when you executed that command. Ruby tried to run the script but couldn't find it in the local/current directory.
I'm not trying to be cruel, but, as a programmer, you'll spend a huge amount of time at the command-line, especially so if you are programming in C/C++, Perl, Ruby, Python, or any non-IDE based language. You have to learn how the OS works otherwise disasters of varying sizes and shapes await you, so, in parallel to learning a language you need to learn how to use, and administer, your OS. You don't have to be a power-user or administrator, but you have to know enough to understand good instructions from ones that don't apply, or are just plain-wrong.
Well I was facing the same problem, I had ruby & rails installed but I couldn't run them on ZSH
The answer is so simple
Just Add the following lines to .zshrc
export PATH="$HOME/.rbenv/bin:$PATH"
eval "$(rbenv init -)"
Then run
source ~/.zshrc
After that to check if ruby & rails are found by ZSH run
ruby --version
rails --verison

shebang for multiple versions

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.

RVM on Ruby Scripts

I need for a Ruby script to be run using an rvm-selected version. I cannot change how the script is invoked, but I can modify the script. The script starts with:
#!/usr/bin/env ruby
Now, based on some information I found (in this question, for example), I tried this:
#!/usr/bin/env rvm-shell ree-1.8.7-2012.02#gitorious
But this only gives me this error message:
/usr/bin/env: rvm-shell ree-1.8.7-2012.02#gitorious: No such file or directory
Now, rvm is available, because this works (but doesn't bring the required ruby/gemset):
#!/usr/bin/env rvm-shell
I've tried this as well:
#!/usr/local/rvm/bin/rvm-shell ree-1.8.7-2012.02#gitorious
But this doesn't bring in the environment ("gem", which is only installed inside that gemset, is not available, for example). If I run that on the command line itself, it does open a shell with the proper environment.
So, has anyone done something like this? How can I fix it?
Does this work?
#!/location/of/rvm/folder/rubies/ree-1.8.7-2012.02#gitorious/bin/ruby

how to write a ruby script running on different system

I have a ruby script, which declare the ruby path in the first line
#! /usr/bin/ruby
But, I need it to be run in different system. And the path of Ruby are different in different system. How to handle this issue?
In unix systems you can get away with
#! /usr/bin/env ruby
This has the effect of using the ruby found on the path. env is a core binary on pretty much every unix.

Resources