"bash: command not found" — PATH, Packages, and the Right Name

The shell searched every PATH directory and didn't find an executable by that name. Three families: not installed, installed outside PATH, or the name you typed isn't the binary's name. Each has a one-command check.

What you'll see

Root causes

The binary genuinely isn't installed

The #1 cause, especially on slim containers and fresh servers. which <cmd> / command -v <cmd> confirm absence; then install via the package manager, not a random download.

Installed but not in PATH (or PATH broken per-context)

Snap binaries (/snap/bin), ~/.local/bin, /usr/sbin for non-admin users, or a PATH reset in cron/su/CI environments (which use minimal env). echo $PATH in the failing context is the whole diagnosis.

Wrong name: versioned commands and package/name splits

python3 not python, aws-cli's aws, nodejs vs node on older Debian. The package installed fine — the binary name is what you're wrong about. dpkg -L <pkg> | grep bin lists what a package actually installed.

Fix it

  1. Confirm absence vs invisibility
    command -v <cmd> ; echo "$PATH"   # if a full path exists elsewhere: locate it first
  2. Find the real binary name for an installed package
    dpkg -L <pkg> 2>/dev/null | grep -E 'bin/'   # shows exactly what got installed and under what name
  3. Add the missing directory to PATH, persistently
    export PATH="$HOME/.local/bin:/snap/bin:$PATH" >> ~/.bashrc   # then source ~/.bashrc (login vs non-login shells matter)
  4. Scripts/CI: use absolute paths or export PATH at the top
    # cron gets a minimal env: PATH=/usr/local/bin:/usr/bin:/bin on line 2 of the crontab, or invoke binaries by full path

Field note

command not found vs Permission denied vs No such file or directory: the first is PATH, the second needs +x, the third (with a full path) is usually a broken interpreter line — see the bad-interpreter error. hash -r after installing into an already-searched directory: bash caches command locations per session and will keep claiming absence until the cache is cleared.

Common questions

Why does it fail only in cron or CI?

Those contexts start with a minimal PATH (often just /usr/bin:/bin). Binaries in /usr/local/bin, ~/.local/bin, or snap dirs vanish. Print PATH from inside the failing context and set it explicitly.

I installed it but the shell still says not found. Why?

Either the new directory isn't in PATH yet (source your rc file or start a new shell) or bash's hash cache is stale (hash -r). Both are 5-second fixes that look like mysteries at 2am.

Ship it right the first time

Our most-documented failures, packaged as ready-to-ship starter kits: Docker, Kubernetes, and Terraform.

Browse the template store →

One-time. Yours to modify. Instant download from the NinjaOps template store.