How to fix "command not found" after installing gems

You've just installed a gem, let's say jekyll, or rails, and it installed just fine. But when you tried to use the gem, you got command not found. Other variations include:

How frustrating! You ask on help forums, search the internet for solutions, but nothing works!

Troubleshooting command line errors is an essential skill to practice. The more familiar you become with certain errors, the faster you can recognize them and fix them. Sometimes, troubleshooting involves reading the error message carefully, or figuring out which part of the message to search for in DuckDuckGo. But what if the message is simply command not found?

In some cases, this could be due to a typo, but when you know you've successfully installed something and typed it correctly, command not found is not very helpful. To understand why the computer sometimes can't find a command that was just installed, let's look at how shells work on macOS.

When you launch the Terminal app (or iTerm2, or Hyper, or any other terminal emulator) on a brand new Mac, you can immediately start using certain commands, like ls and cd. How does the computer know about those commands and where to find them? It follows the PATH!

PATH is an environment variable that contains a list of locations where the computer can find programs to run. The computer looks in each location in order of appearance until it finds the program (or not). You can view this list by running echo $PATH. Many programs that you might run from the command line on macOS, such as pwd, whoami, or cal, live in /bin or /usr/bin. On a fresh macOS installation, the PATH already contains /bin and /usr/bin, which is why you can type whoami and know thyself on a brand new Mac.

When you install new programs, such as Ruby gems like Bundler, Jekyll, or Rails, they might get installed in a location that is not already included in the PATH. If you don't add this new location to the PATH, the computer won't know to look for it there, which is why you'll get "command not found".

To let the shell know about the new location, we can add it to the existing PATH list. For example, if we wanted to add the location /usr/local/opt/ruby/bin, we would add it like this:

export PATH="/usr/local/opt/ruby/bin:$PATH"

export is the command used to set environment variables. The PATH variable expects a list of directories separated by a colon (:). Instead of writing all the locations one by one, we can add any new directories to the existing ones by adding :$PATH at the end. $PATH represents the current list of directories that the shell knows about.

Sometimes, you might be installing a newer version of a command or program that already exists on macOS. To make sure the shell uses the new version, we tell it to look in the new location first, by adding it before the existing list of locations, like we did above.

Anytime you run an export command to set an environment variable, it only applies to the current shell session. To test this, run:

export FOO=bar

and then:

echo $FOO

You should get bar.

Now open a new Terminal tab (command-t) and run echo $FOO. You will get nothing back. So, how can we set the PATH permanently, or at least have it automatically set to the right value for every new terminal session? We do that by adding the export PATH line to a file that gets read by the terminal every time you start a new session. The name of that shell startup file depends on which shell you are using (typically .zshrc or .bash_profile). Read my shell guide to learn more.

Thanks, Moncef, that's some useful knowledge you're dropping there. But how am I supposed to know where the program I'm trying to use got installed? How can I add it to the PATH if I don't know where it is? Do you expect me to search my entire hard drive? What if the program exists in multiple locations? Which one do I pick?

Those are all valid questions. I feel your pain. The answer is complicated because it depends on how you installed Ruby on your Mac. If you used my script, you wouldn't have to worry about any of this because it automatically sets everything up for you. If you installed Ruby with Homebrew, you can get back on track by either running my script, or adding the Homebrew gems location to your PATH by following my definitive guide to installing Ruby gems on a Mac.

Another reason why commands might not be found, or why the newer version of a tool is not being used, is that the shell startup file might have been updated as part of the installation process (which is something my script does). When you make changes to the shell startup file, they don't take effect right away. You have to "refresh" it by either using the source command, such as:

source ~/.zshrc

Or by quitting and relaunching your terminal app, or by opening a new tab. It's the old have you tried turning it off and on again?

One more reason for a missing command is when switching between Ruby versions. One of the advantages of using a Ruby manager like chruby (which is what my script installs) is that you can easily install multiple versions of Ruby at the same time, and switch between them. However, each time you install a gem, it only gets installed in that specific version of Ruby. So, if you've just installed a new version of Ruby, you'll have to install the gem again.

Side Notes

Setting the PATH is not required to use a particular command. You can always call programs by their full location. For example, if you type /usr/bin/ruby -v, it will always use the Ruby program in /usr/bin (the one that came preinstalled on macOS), and you should get ruby 2.6.3p62 on Catalina. Similarly, to switch to the version that my script installs, you can find out where it is (assuming your shell startup file is configured to use it) by typing which ruby and then copy and paste the output, add a space and then -v, and you should see ruby 2.7.2p137 or later. The point of setting the PATH is to be able to use the short program name without having to remember where it is located.