the path variable and modifying it

2020-04-15

 | 

~3 min read

 | 

565 words

I decided to start exploring Rust and one of the first things you do when you install Rust, if you don’t want to have to source it every time you launch a terminal is add it to your PATH variable.

In the past, this is the kind of complexity that I’ve allowed to pass by me without diving in. Today, however, I wanted to learn what exactly was happening.

So, for starters: what is PATH? Let’s start by looking at it directly:

$ echo $PATH
/Users/stephen/.nvm/versions/node/v12.16.1/bin:/Users/stephen/.cargo/bin:/usr/local/bin:/usr/bin:/bin:/usr/sbin:/sbin

Here we can see I have several “paths” concatenated together.

When launching a terminal, these are all available. In my case they include nvm for Node version management, and cargo for Rust. The others, if I’m not mistaken, are the standard paths that ship with MacOS - inferring from their names they’re the regular and secure (?) bins.1

So, the PATH lists directories that the operating system will look in for programs. It’s a short hand.

How do we add to this list? Natalie Weizenbaum (nex3) put together a useful Gist on how to add new programs to the PATH for different operating systems.

For Mac, her recommended approach was:

# ~/.bash_profile
export PATH="your-dir:$PATH"

This mirrors the recommended approach from “the Book” on Rust:

# ~/.bash_profile
$ export PATH="$HOME/.cargo/bin:$PATH"

Problem solved, right?

Almost.

I wanted to understand what the colon was doing there. It’s sitting right there between the path to our new director (e.g., $HOME/.cargo/bin) and the existing expanded PATH (i.e., it’s $PATH, not just PATH).

What does the colon do?

I started with some web searches that seemed promising. For example, I learned that in Bash, a colon separating arguments will “do nothing beyond expanding arguments and performing redirections. The return status is zero.” A colon _within a shell parameter expansion, however, behaves differently - acting more as a fallback.

But that’s actually not what we’re doing here.

Let’s take a look:

$ export TEST="123"
$ export TEST="456:$TEST"
$ echo $TEST
456:123

It’s just a character that we’re placing between the new path and the existing path(s). Why? Because the colon is simply how paths are delimited.

A final point: Ordering.

Among the comments on Natalie’s Gist was one from FTheodore:

I would just like to say that you should consider using export PATH="$PATH:your-dir" instead. This will append the new path to the variable. Adding the absolute path to the beginning of the file will make the system search that directory first every time. This is not recommended as it can cause problems with system programs and it adds unnecessary delay.

Now that we know that the : is acting as a separator between our new path and the existing paths, FTheodore’s comment makes sense. He’s arguing that we should not be burying the system defaults beneath the programs we add, but allow those to be searched first and then continue on to the new program.

Makes sense to me.

So, with a slight tweak, the final solution for adding to our PATH variable is:

# ~/.bash_profile
export PATH="$PATH:your-dir"

Footnotes

  • 1 The definition of a bin was another topic I hadn’t really explored either. It appears that when it’s a directory, it refers to a location of binary executables and when it’s a file extension, it’s the binary itself. (Source: What is Bin?)

Hi there and thanks for reading! My name's Stephen. I live in Chicago with my wife, Kate, and dog, Finn. Want more? See about and get in touch!