Shell Tricks: Custom ruby shebangs for speed
This is part 2 of my series on tricks I’ve used in shell scripts. In this post, I’ll share a few ways a custom shebang can be used in ruby scripts.
If you don’t know what a “shebang” is — it is the first line commonly seen
in scripts that starts with #!
. When a script is run, this line determines
the program to run to interpret the rest of the script. Wikipedia has a more
thorough explanation.
In a ruby script, this is typically one of the following:
#!/usr/bin/env ruby
#!/usr/bin/ruby
The first version will use the first ruby
found on your PATH
to execute
the script. If you are using a ruby version manager (chruby, rbenv, RVM), a
script with the first shebang will use the correct ruby. Most ruby scripts in
the wild use this version.
The second version specifies a specific ruby to execute the script,
/usr/bin/ruby
. On OS X this is ruby 2.0.0. If additional rubies are
installed, running a script with the second shebang will always use OS X’s
ruby 2.0.0. This isn’t usually desirable, which is why most scripts use the
first form.
Why not always use the first version?
Two reasons. First, in some cases it actually is desirable to hard-code the program that will execute your script. Second, you can pass arguments to the program in a shebang with the second version but not the first.
What?
I’ll use a real world example from a little script I wrote recently,
shotty
, where both of these reasons applied.
Glossing over the details of the script itself, it is a ruby script for use on OS X. OS X comes pre-installed with ruby 2.0.0. That version is pretty old, but it means a Ruby script is fair game for all OS X users without having to install anything extra.
Since I can only rely on ruby 2.0.0 features, I want to force the script to
run on that at all times. The easiest way to accomplish this is to specify
/usr/bin/ruby
in the shebang.
I decided my script would not use any gems. Executing the script with ruby
--disable=gems
showed a significant speed increase.
Putting both ideas in place, the shebang for shotty
looks like:
#!/usr/bin/ruby --disable=gems
The env
version does not work:
#!/usr/bin/env ruby --disable=gems
A user on StackExchange sums up why it doesn’t work, and some additional pros and cons.
More shebangs
Rails runner
This is like running rails runner script.rb
:
#!/usr/bin/env /Users/priddle/work/rails/bin/rails runner
Why? You want to run ./script.rb
instead of rails runner script.rb
. I’ve
never used this because I don’t like the hard-coded path to rails
in the
shebang. But it’s there 😀
AppleScript
Most AppleScript is shared as compiled files. OS X includes osascript
which
can be used as a shebang to run non-compiled AppleScript code. This is
probably slightly slower than using a compiled script, but I’ve never noticed
a difference.
#!/usr/bin/env osascript
...AppleScript code