LearnWithShobhan

How the shell finds commands: PATH and environment variables explained

Shobhan Biswas··5 min read
>_From the course CLI Mastery: 57 lessons, lifetime access.

You type ls, press Enter, and a list of files appears. It feels like magic, but there is no magic: ls is just a file on your disk, and your shell has to find it first. The place it looks is controlled by one environment variable called PATH. Once you understand it, errors like command not found stop being mysterious.

What happens when you run a command

Say you type ls in your terminal:

  1. The terminal sends the text ls to the shell (the terminal only carries text, as explained in terminal vs shell).
  2. The shell keeps a list of directories to search. It checks the first one for a file called ls. Not there? It checks the next, then the next.
  3. When it finds a file named ls, it runs it. That file contains machine code, so the operating system executes it using low-level system calls.
  4. Whatever the program prints goes back to the shell, and the shell relays it to your terminal window.

So a command like ls, mkdir or echo is simply a program stored somewhere on disk. The shell's job is to know where to look.

Environment variables: key-value pairs for the shell

If you've used any programming language, you know variables: a name holding a value. The shell has the same idea. Variables that the shell and the programs it launches can read are called environment variables. PATH is one of them. USER, which holds your username, is another.

To read a variable, put a dollar sign in front of its name and print it with echo:

bash
$ echo $USER
shobhan
$ echo $PATH
/usr/local/bin:/usr/bin:/bin:/usr/sbin:/sbin

Your output will differ, and on a machine you've used for a while it is usually longer, because installers and you add things over time. The important detail is the colon. PATH is not one directory; it is several directories separated by colons. The shell searches them from left to right.

To read a long PATH more easily, print one directory per line:

echo $PATH | tr ':' '\n'

Find where a command lives with which

You don't have to guess which directory a program came from. Ask the shell:

bash
$ which ls
/bin/ls
$ which mkdir
/bin/mkdir

The exact location depends on your system (many modern Linux distributions show /usr/bin/ls), but the idea is the same. When you ran ls, the shell checked the PATH directories in order and found the file in the one which just printed.

You can even look inside. List the directory and you'll see the commands you use every day as plain files:

cd /bin
ls -l

In ls -l output, the first character tells you the type of entry: - means a regular file and d means a directory. Every command in that folder starts with a dash, so each is a file. If you try to cat one of them you'll see unreadable characters, because it holds compiled binary code meant for the machine, not for you.

Why you get command not found

If the shell walks through every directory in PATH and finds no file with that name, it gives up:

bash
$ somethingrandom
zsh: command not found: somethingrandom

That error does not mean the command doesn't exist anywhere on your computer. It means it isn't in any directory listed in PATH. This is the cause of a very common situation: you install a tool, but your terminal can't find it. Usually the tool's folder just isn't in PATH yet.

Adding your own folder to PATH

PATH is editable. To make the shell also search a folder of your own scripts, add it:

export PATH="$HOME/bin:$PATH"

Two things to notice:

  • export makes the variable available to programs the shell starts.
  • The new folder goes in front, followed by the old PATH. Because the shell stops at the first match, order matters: a program in $HOME/bin will win over one with the same name further along. Put the folder at the end instead (PATH="$PATH:$HOME/bin") if you'd rather system programs win.

This is also the key to writing your own commands: any executable script placed in a PATH directory becomes a command you can run by name. There's more on scripts in Shell scripting for beginners.

Free to watch. Get all 57 lessons →

Key takeaways

  • ✓A command like ls is just a program file; the shell has to find it before it can run it.
  • ✓PATH is an environment variable: a colon-separated list of directories the shell searches from left to right.
  • ✓echo $PATH shows it, which ls shows where a command was found, and command not found means no PATH directory had that file.
  • ✓Put a folder at the front of PATH to make its programs win, and add the export line to your shell config to keep it.

Learn the command line properly, once

CLI Mastery is 57 short lessons that take you from "what is a shell" to scripting and running a web server on AWS. Every idea is drawn first, then done live. Lifetime access, and three lessons are free to watch.

Free download

Linux command line cheat sheet

One printable page: navigation, files, permissions, pipes, processes, scripts and SSH.

Occasional emails with new tutorials and courses. Unsubscribe any time.

Keep reading