“Command Not Found” in Linux: A Real Troubleshooting Checklist

“Command Not Found” in Linux: A Real Troubleshooting Checklist

You run a command and bash throws back the same unhelpful line every time:

$ terraform init
bash: terraform: command not found

Most guides tell you to “check your PATH” and stop there. That’s step one, not the whole answer — and it’s rarely even the actual problem once you’ve been doing this a while. Below is the checklist I actually run through, in the order that catches the most common causes first.

1. Rule out a typo

Obvious, but worth a second look, especially over SSH where autocomplete sometimes doesn’t kick in. Run it again, slowly, and check for anything odd — invisible unicode characters pasted from a doc, a trailing space, wrong case (Linux is case-sensitive: Terraform and terraform are different commands).

2. Confirm it’s actually installed

Don’t assume — verify. command -v is the POSIX-portable way to check if something resolves to an executable, alias, or function:

$ command -v terraform
$ echo $?
1
bash — user@server: ~
$ command -v terraform$ echo $?1# empty output + exit 1 → not found on PATH $ find / -name "terraform" -type f 2>/dev/null/opt/terraform/terraform $ echo $PATH/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin# /opt/terraform is missing from PATH $ export PATH="$PATH:/opt/terraform"$ command -v terraform/opt/terraform/terraform
The full diagnosis: not on PATH → find the binary → confirm PATH → fix it.

Empty output and a non-zero exit code means bash genuinely can’t find it anywhere on your PATH. Next question: is it installed at all, just not linked into PATH?

$ find / -name "terraform" -type f 2>/dev/null
/opt/terraform/terraform

There it is. Installed, but sitting in a directory bash never looks at.

3. Check what’s actually on your PATH

$ echo $PATH
/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin

/opt/terraform isn’t in that list, so bash has no way of knowing it exists. Fix it for the session:

export PATH="$PATH:/opt/terraform"

And to make it permanent, add that line to the right shell config file — which brings up the next, more subtle problem.

4. The PATH trap: interactive vs. non-interactive, login vs. non-login shells

This is where most people waste an hour. You add the export line to ~/.bashrc, it works fine when you SSH in and test it manually, then it silently fails in a cron job or a systemd service. Why? Because non-interactive, non-login shells don’t source .bashrc the same way an interactive login shell does.

The short version:

  • Login shell (first shell after SSH login, or a TTY login) reads /etc/profile, then the first of ~/.bash_profile, ~/.bash_login, or ~/.profile it finds.
  • Interactive non-login shell (opening a new terminal tab on an already-logged-in session) reads ~/.bashrc.
  • Non-interactive shell (a script, a cron job, most CI runners) reads neither by default — it inherits whatever PATH the parent process handed it.

So a PATH export sitting only in ~/.bashrc will never be seen by a cron job. If a script needs a specific PATH, set it explicitly at the top of the script rather than relying on shell startup files at all — it’s more predictable and doesn’t break the next time someone changes their login shell.

5. sudo has its own PATH

This one catches people constantly: a command works fine as your user, then “command not found” the moment you add sudo in front of it.

$ sudo -V
Sudo version 1.9.13p3

By default, sudo doesn’t inherit your shell’s PATH. It uses secure_path, defined in /etc/sudoers, which is a fixed, restricted list — usually just the standard system directories. If your tool lives in /opt/terraform or anywhere non-standard, sudo terraform will fail to find it even though plain terraform works, because secure_path doesn’t include it. You either add the directory to secure_path with visudo, or call the binary by its full path when using sudo.

6. Was it there before, and did something remove it?

If a command used to work and suddenly doesn’t, someone or something uninstalled it — a package cleanup, a colleague running apt autoremove, an image rebuild. Check the package manager’s log instead of guessing:

# Debian/Ubuntu
$ grep -i "remove" /var/log/dpkg.log

# RHEL/CentOS/Fedora
$ grep -i "erase" /var/log/dnf.log

This turns “it just stopped working” into an actual answer with a timestamp attached.

7. Check for shadowing — alias, function, or another binary with the same name

Sometimes the command *is* found, just not the one you expected. type tells you more than which does here, because it also reports builtins, aliases, and functions — not just files on disk:

$ type cd
cd is a shell builtin
bash — user@server: ~
$ type cdcd is a shell builtin $ type llll is aliased to `ls -alF' $ type -a python3python3 is /usr/local/bin/python3python3 is /usr/bin/python3# first match wins: /usr/local/bin shadows /usr/bin $ which python3/usr/local/bin/python3# which only shows the first match
type reveals builtins, aliases and every binary competing for the same name.
$ type -a python3
python3 is /usr/local/bin/python3
python3 is /usr/bin/python3

which would only ever show you the first match on PATH. type -a shows every place a name resolves, in the order the shell would check them — which is exactly what you need when two versions of the same tool are fighting for the same name.

The fast version

  1. Retype the command — rule out typos and case.
  2. command -v <name> — is it installed and on PATH at all?
  3. find / -name "<name>" -type f 2>/dev/null — is it installed but not on PATH?
  4. echo $PATH — what’s actually being searched?
  5. Setting PATH in a script? Don’t rely on .bashrc — non-interactive shells won’t read it.
  6. Using sudo? Remember it has its own secure_path, separate from yours.
  7. Command used to work? Check dpkg.log / dnf.log for removal history.
  8. type -a <name> — check for aliases, functions, or a shadowing binary.

“Command not found” is one error message covering at least half a dozen distinct causes. Working through them in this order — cheapest checks first — gets you to the real answer faster than guessing.

Keep reading

Similar Posts

Leave a Reply

Your email address will not be published. Required fields are marked *