Manage your PATH with a Ruby script, using a single line of Bash
I'm a huge fan of the POSIX interface, but I really find Bash to be gross. I much prefer Ruby! Since I need to modify my shell config files every now and then by messing with the PATH
in unpleasant ways, I really would rather take care of it with a language that is elegant and fun to program in.
Since environment propagation between shell environments is one-way only, I thought of a nice solution in which I could use Ruby to perform all the logic of modifying the PATH
variable, while still capturing the results in my.bashrc
config script. By defining the function setpath() { $(ruby ~/.pathconfig.rb SET); }
in my .bashrc
, I can configure PATH
just how I need to at any given point. By storing the original PATH
in an environment var at the same time, I can easily return the PATH
to it's original state with a single command. Shiny!
Ruby is really convenient for this becuase you can nicely arrange your path entries in the order you want, then use cool tricks like the |
union operator to seamelessly merge with the existing PATH
. Plus, things like sorting and performing complex operations on collections are not messy with Ruby; you can easily implement functional, or rule-based directives for deciding your PATH
.
Oh, and the only reason I use the funny name VANILLA_PATH
is because I just thought it would reduce the likelihood of clashing with other variable names; you never know who is modifying the environment alongside your nifty script.
#!/usr/bin/env ruby
#
# PATH management via Ruby
#
# The following two functions accompany this script and
# shoudl be defined in ~/.bashrc, ~/.profile, or ~/.bash_profile:
#
# setpath() { $(ruby ~/.pathconfig.rb SET); }
# resetpath() { $(ruby ~/.pathconfig.rb UNSET); }
#
abort unless ARGV.first
if ARGV.first == 'SET'
HOME = ENV['HOME']
additions = [
# Ensure binstubs have priority within a local Bundler project, and reduce use of `bundle exec`
'./.bundle/bin',
# NPM - Node.js package manager
'/usr/local/share/npm/bin',
"#{HOME}/usr/local/share/npm/bin"
]
# Sort the path entries using Ruby's comparison operator, to achieve ideal precedence
newpath = ENV['PATH'].split(':').uniq.sort! {|a, b| b.length <=> a.length }
# Prepend additions to PATH, and remove duplicates with Set#union
newpath = (additions | newpath).join ':'
oldpath = ENV['PATH']
else
newpath = ENV['VANILLA_PATH']
oldpath = nil
end
puts "export PATH=#{newpath};"
puts "export VANILLA_PATH=#{oldpath}"
P.S. Here is the gist