We're sorry but this app doesn't work properly without JavaScript enabled. Please enable it to continue.

The PATH Environment Variable in Linux, Explained

Boot.dev Team
Boot.dev TeamProgramming course authors and video producers

Last published

Table of Contents

Sooner or later, every developer installs a program, types its name into the terminal, and gets hit with an error: command not found. Usually, the culprit is the PATH environment variable: the list of directories your shell searches when you try to run a command. To understand your PATH (and how to fix it when it breaks), it helps to understand how programs run on Linux in the first place. So that's where we'll start: compiled vs interpreted programs, executables, shebangs, and environment variables. Then we'll dig into the PATH itself and how to change it.

All the content from our Boot.dev courses are available for free here on the blog. This one is the "Programs" chapter of Learn Linux. If you want to try the far more immersive version of the course, do check it out!

Compiled vs Interpreted Programs: What's the Difference?

Click to play video

A program is just a set of instructions that a computer can execute, and an "executable" is just a file that contains a program. The words "program" and "executable" are often used interchangeably. Broadly speaking, there are two types of programs:

  • Compiled programs
  • Interpreted programs

A compiled program is a program that has been converted from human-readable source code into machine code (binary). Machine code is a set of instructions that a computer can execute directly: your computer's CPU is hardware that's been designed to execute machine code. Programming languages like Go, C, and Rust produce compiled programs.

An interpreted program is a program that is executed by another program. The program that executes the interpreted program is called an interpreter. The interpreter reads the source code of the interpreted program and executes it. Programming languages like Python, Ruby, and JavaScript are typically interpreted as they run, which means your computer needs to have the interpreter installed to run the program.

Another example is .sh shell script files. Those are interpreted by the shell program.

The which command tells you the location of an installed command line program. For example, which sh asks for the location of the sh (shell) program. On most machines it lives at /bin/sh.

If you were to cat /bin/sh, you wouldn't see readable text. You'd see a screen full of garbage. That's because your sh program is a compiled executable, probably written in C. The raw machine code isn't meant for human eyes.

A file with a .sh extension, on the other hand, is a shell script. It's a text file that contains commands that will be interpreted and run by the sh program. They are both executable programs, but only one can be run without the help of another program.

How Do You Run an Executable in Linux?

You're familiar with the idea of reading and writing data into files. But what about executing them? Executable files are just files where the data stored inside is a program that you can run on your computer.

You can run a file in your shell by typing its filepath (assuming it has execute permission):

mydir/program.sh

Interestingly, if the program is in the current directory (in this example, the mydir directory), you need to prefix it with ./ to run it:

./program.sh

As far as file paths go, ./program.sh and program.sh are the same. The dot (.) is an alias for the current directory. We need the prefix when running executables so that the shell knows we're trying to run a file from a file path, not an installed command like ls, mkdir, chmod, etc.

What Is a Shebang?

Running an executable by its file path works out-of-the-box for files that are compiled executables. But what about scripts that need to be interpreted by another program? The computer needs to be told what program to use to interpret the file.

A "shebang" is a special line at the top of a script that tells your shell which program to use to execute the file.

The format of a shebang is:

#! interpreter [optional-arg]

For example, if your script is a Python script and you want to use Python 3, your shebang might look like this:

#!/usr/bin/python3

This tells the system to use the Python 3 interpreter located at /usr/bin/python3 to run the script.

sh vs Bash vs Zsh: What's the Bourne Shell?

Depending on your system, you're probably running one of a few different shells:

  • If you're using Ubuntu on WSL, you're probably running a Bash shell.
  • If you're using macOS, you're probably running a Zsh shell.
  • If you're running a raw Linux installation, I pray you already know what you're using.

To get hand-wavy about it, I want to explain the difference between the 3 shells you're likely to encounter:

  • sh: The Bourne shell. This is the original Unix shell and is POSIX-compliant. It's very basic and doesn't have many quality-of-life features.
  • bash: The Bourne Again shell. This is the most popular shell on Linux. It builds on sh, but also has a lot of extra features.
  • zsh: The Z shell. This is the most popular shell on macOS. Like bash, it does what sh can do, but also has a lot of extra features.

Both zsh and bash are "sh-compatible" shells, meaning they can run .sh scripts, but they also have extra features that generally make them more pleasant to use. For most purposes, the differences between zsh and bash are not super significant, and everything in this article works in both.

What Are Environment Variables in Linux?

You can create and use local shell variables in your shell:

name="Lane"
echo $name
# Lane

There is another type of variable called an environment variable. They are available to all programs that you run in your shell.

You can view all of the environment variables that are currently set in your shell with the env command.

To set a variable for your current shell session, use the export command (it won't persist if you close the terminal):

export NAME="Lane"

You can then use the variable in your shell, just as before:

echo $NAME
# Lane

The interesting part is that programs and scripts you run in your shell can also use that variable. For example, if we have a script called introduce.sh with the following contents:

#!/bin/sh
echo "Hi I'm $NAME"

We can run it and it will use the NAME environment variable we set earlier:

./introduce.sh
# Hi I'm Lane

You can also temporarily set a variable for a single command, instead of exporting it for the whole session:

NAME="Gollum" ./introduce.sh
# Hi I'm Gollum

And you can use the unset command to remove an environment variable from your current shell session:

unset NAME

What Is the PATH Variable in Linux?

This is the most important section in this entire article! Listen up.

There are environment variables that are sort of "built-in" to your shell. By "built-in" I just mean that different programs and parts of your system know about them and use them. The PATH variable is one of those.

If it weren't for the PATH, you'd have to remember the filesystem path of every executable you wanted to run in your shell. Instead of just running ls, you'd have to run /bin/ls (or wherever the ls executable lives on your system). That's not very convenient.

The PATH variable is a list of directories that your shell will look into when you try to run a command. If you type ls, your shell will look in each directory listed in your PATH variable for an executable called ls. If it finds one, it will just run it. If it doesn't, it will give you an error like: "command not found."

Take a look at your current PATH variable:

echo $PATH

You should see a list of directories separated by colons (:). A realistic PATH might look something like this:

/usr/local/bin:/usr/bin:/bin:/usr/sbin:/sbin

Which means your shell will use all these directories to look for executables:

  • /usr/local/bin
  • /usr/bin
  • /bin
  • /usr/sbin
  • /sbin

How to Add a Directory to Your PATH

A common problem you'll run into when installing programs via the terminal is that after installing, you try to run the program and get an error like this:

$ my-new-program
-bash: my-new-program: command not found

Nine times out of ten, it's because the program is installed in a directory that's not in your PATH variable. Oftentimes when you install a program using the CLI, it will print a message during the installation process that tells you where the executable was installed. Don't let your eyes glaze over when your terminal prints important messages! Sometimes you just gotta rtfm.

To add a directory to your PATH without overwriting all of the existing directories, use the export command and reference the existing PATH variable:

export PATH="$PATH:/some/new/directory"

The $PATH part is a reference to the existing PATH variable. The : separates the existing directories from the new directory that you're adding.

Keep in mind that this change only lasts for your current shell session: once you close your terminal, it's gone. To make a PATH change permanent, you add that same export line to your shell's configuration file, like .bashrc or .zshrc, so it runs automatically every time you open a new shell.

If you want to practice this hands-on (including intentionally breaking your PATH and fixing it again in a safe sandbox), that's exactly what you'll do in the Learn Linux course.

Frequently Asked Questions

How do I permanently add a directory to my PATH in Linux?

Add the export line, like export PATH="$PATH:/some/new/directory", to your shell's configuration file: .bashrc for Bash or .zshrc for Zsh. The export command on its own only lasts for your current shell session.

Why does my terminal say command not found after I install a program?

Nine times out of ten, the program was installed to a directory that isn't listed in your PATH variable. Find where the executable was installed (the installer usually prints it) and add that directory to your PATH.

What is the separator in the Linux PATH variable?

A colon. The PATH variable is a single string containing a list of directories separated by colons, for example /usr/local/bin:/usr/bin:/bin. When you append a new directory, you separate it from the existing list with a colon.

What is the difference between sh and bash?

sh is the Bourne shell, the original POSIX-compliant Unix shell, and it's very basic. Bash, the Bourne Again shell, builds on sh with many extra quality-of-life features and is the most popular shell on Linux. Bash can run .sh scripts because it's sh-compatible.

Why do I need ./ to run a script in the current directory?

The ./ prefix tells your shell that you're running a file at a filepath rather than an installed command. Without it, the shell only searches the directories listed in your PATH variable, and your current directory usually isn't one of them.

Related Articles