sixty4bit sixty4bit - 1 year ago 57
Ruby Question

Ubuntu: Kernel#system fails (returns nil) when running the Unix "hash" command

I ran into an interesting problem while developing a gem that only seems to happen on Ubuntu. My Ruby is version 2.2.2 installed with the rbenv tool. I am building a CLI (Tool A) that depends on another utility (Tool B) being installed on the machine. At the point when Tool B is called there is a guard clause that prints an error message if Tool B isn't found, like this:

fail "Can't do it: missing 'Tool B' utility" unless system("hash tool-b")

I had no problems with this on OSX, but on Ubuntu
system("hash tool-b")
always returns
(command failed). When printing the exit code from within a Ruby interpreter (
), I get
instead of

The strange thing is that if I run
hash tool-b
directly from the command line, the process exits successfully with a status of
. This seems to happen for me when checking for any utility on Ubuntu from within Ruby with
system("hash <utility>")
. I've changed the program to use
system("which tool-b")
instead of
but am still interested to know if there is something particular to my setup that might be doing this (it's a vanilla Ubuntu 14.04 box on Amazon EC2 with pretty much nothing but rbenv, Ruby 2.2.2, and my gems), or something about Ubuntu + Ruby that I don't get.

Summary of the commands I'm running on the different platforms:

fail "Can't create cartridge: missing 'cartridge' utility" unless system("hash cartridge") # offending Ruby code

$ hash cartridge
$ echo $?
=> 0

system("hash cartridge")
=> nil
puts $?
=> ... exit 127

system("hash cartridge")
=> true
puts $?
=> ... exit 0

Answer Source

Kernel#system uses the system shell, i.e. /bin/sh to execute. hash was only added to the Base System in POSIX.2013, before that, it was optional. I believe dash, the default system shell Ubuntu uses is not yet POSIX.2013 compliant, and thus does not have hash (yet).

macOS / OSX uses Bash as its system shell, which does have hash.