// notes
Linux: “command not found” — PATH, ifconfig, pip
command not found on Linux: how to trace a binary through PATH, why sudo and login shells see a different path, and what replaces ifconfig and pip
bash: ifconfig: command not found and bash: pip: command not found look like the same breakage, but the causes differ: in the first case the binary is not installed, in the second it is installed and its directory is missing from PATH. Below is how command lookup in PATH works and the type -a, command -v, echo $PATH, hash -r sequence that tells you what to fix
Symptom
The error appears when the shell finds the command in none of the directories listed in PATH. The wording depends on the shell and the locale; the meaning is the same
$ ifconfig
bash: ifconfig: command not found
$ pip --version
bash: pip: command not found
$ iptables -L
bash: iptables: command not foundiptables is here as an example of a command from /usr/sbin: under sudo it may run, while a regular user cannot start it. A similar-looking error shows up when a database is set up: PostgreSQL: connection refused and installing PostgreSQL
Diagnosis
Start by asking the shell where it looks for the command. command -v prints the path and returns 0 when the command is found, and prints nothing with exit code 1 when it is not
$ command -v ip
/usr/bin/ip
$ command -v ifconfig
$ echo $?
1type -a lists every match: aliases, functions, builtins and binaries, in selection order
$ type -a python3
python3 is /usr/bin/python3
$ type -a echo
echo is a shell builtin
echo is /usr/bin/echoNext, inspect PATH itself: a colon-separated list of directories searched left to right
$ echo $PATH
/home/$USER/.local/bin:/usr/local/bin:/usr/bin:/bin
$ echo $PATH | tr ':' '\n'
/home/$USER/.local/bin
/usr/local/bin
/usr/bin
/binIf the directory is not in the list, installing the package alone will not make the command visible. Check whether the binary is physically on disk
$ ls -l /usr/sbin/ifconfig 2>&1
ls: cannot access '/usr/sbin/ifconfig': No such file or directoryNo file means the package is at fault. A file exists but the command is not found means PATH is at fault. One more source of confusion: bash caches resolved paths in a hash table, so a freshly installed command may stay invisible until hash -r
Cause
PATH is an environment variable read by the shell and by many programs. The first match wins, so directory order matters. If a directory is absent from the list, the command does not exist for the shell even when the file is on disk
On many systems /sbin and /usr/sbin are added to PATH for root only. A regular user does not see them, so iptables or visudo reports command not found while sudo iptables works
By default sudo resets the environment through env_reset and substitutes its own PATH from the secure_path directive in /etc/sudoers, which usually includes /usr/sbin
$ sudo env | grep '^PATH='
PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/binThe second source of mismatch is the shell type. A login shell (SSH login, su -, bash --login) reads /etc/profile and ~/.bash_profile or ~/.profile. A non-login interactive shell (a terminal in a graphical session, plain bash) reads only ~/.bashrc. A PATH line added to just one of them will be missing in the other mode
The third cause is the command hash. Bash remembers the path to a binary it has resolved and does not re-read PATH, so a freshly installed command stays missing until hash -r or a new session
python3 -m pip is more reliable than pip: a system can have several Pythons, and a versionless pip points at the wrong one. The ~/.local/bin directory, where pip drops user scripts, is not in PATH by default either
Fix
The analysis leaves two scenarios. The package is not installed: install it. The command exists but its directory is not in PATH: add the directory
Scenario 1: ifconfig. On Debian and Ubuntu it ships in net-tools, which is not installed by default. The replacement is ip from iproute2
$ ip -brief address
lo UNKNOWN 127.0.0.1/8 ::1/128
eth0 UP 192.0.2.10/24If you specifically need the familiar ifconfig, for an old script:
$ sudo apt update
$ sudo apt install net-tools
$ sudo /usr/sbin/ifconfig -aThe full path sidesteps the PATH issue for the moment: under sudo the /usr/sbin directory is available through secure_path. Installing net-tools only for a manual check is not worth it; ip does more and is already present
Scenario 2: pip. On Debian and Ubuntu the package is python3-pip and it provides pip3. Run it as python3 -m pip to avoid mixing up interpreters
$ sudo apt update
$ sudo apt install python3-pip
$ python3 -m pip --version
pip <version> from .../dist-packages/pip (python 3.x)On Fedora and RHEL the package is python3-pip, on Arch it is python-pip, and ip comes with iproute2. Verify package names with your distribution package manager
Scenario 3: ~/.local/bin. This is where scripts from pip install --user and standalone tools land. The directory is often missing from PATH; add it to ~/.profile for login shells and to ~/.bashrc for interactive ones
# ~/.profile and ~/.bashrc
export PATH="$HOME/.local/bin:$PATH"Apply it without re-logging in and reset the hash:
$ . ~/.bashrc
$ hash -r
$ command -v <tool>
/home/$USER/.local/bin/<tool>hash -r affects only the current session: a new terminal starts with an empty hash. When the command must be available to all users, the directory is added through /etc/profile.d/*.sh, which is an administrator task. If the message is just command not found, the command-not-found package on Ubuntu prints the name of the package that provides the command
Verify
Verify with three commands: where the command is, what is in PATH, and whether the binary responds
$ command -v ifconfig || echo "not in PATH"
not in PATH
$ command -v pip3 || echo "not in PATH"
/usr/bin/pip3
$ ip -brief address
lo UNKNOWN 127.0.0.1/8 ::1/128
eth0 UP 192.0.2.10/24For ifconfig the output is empty: the net-tools binary lives in /usr/sbin, which is not in a regular user's PATH, so the || echo branch fires. The full path from the Fix section bypasses this: sudo /usr/sbin/ifconfig -a
PATH order and duplicates are easier to read line by line
$ echo $PATH | tr ':' '\n' | nl
1 /home/$USER/.local/bin
2 /usr/local/bin
3 /usr/bin
4 /binIf command -v prints a path and returns 0, the command will run in this shell
$ command -v python3 >/dev/null && echo ok
okPitfalls
- `hash -r` only helps in the current shell. A new terminal re-reads
PATH, so the edit from~/.bashrcalready applies there - A `PATH` line in `~/.bashrc` is invisible to non-interactive sessions.
ssh host command, cron and systemd services do not read an interactive profile: they need~/.profile, anEnvironment=directive in the unit file, or the full path to the program - `sudo` does not inherit your `PATH`.
sudo -Eworks only whenSETENVis allowed insudoers; otherwise usesudo env "PATH=$PATH" <command>or the full path - `PATH` order decides. Putting
$HOME/.local/binbefore/usr/binmakes a same-named user command shadow the system one — sometimes exactly what you want, sometimes the source of mysterious failures - The system Python on Debian and Ubuntu is marked externally managed. A plain
pip installfails with anexternally-managed-environmenterror; user packages belong invenvorpipx, notsudo pip - Do not pull in `net-tools` blindly. Old scripts using
ifconfigandnetstatkeep working, but new calls are better moved toipandssfromiproute2
Takeaway
Command not found is one of two cases: the binary is absent, or its directory is missing from PATH. command -v and type -a reveal the first, echo $PATH the second, and hash -r resets the cache after an install. The login versus non-login shell difference explains why a command works in one terminal and disappears in another or under sudo
If you run many servers and keep hitting puzzles like this, see infrastructure as code. When the problem is in the application environment rather than the shell, backend and API development is the next step
Related notes
pkill -f kills itself: the pattern matches the command line
pkill -f and pgrep -f match the pattern against the whole command line, including the bash -c wrapper. Why the command kills itself and which filters help
Nix on CachyOS: install impossible — run it rootless
Nix will not install when the root is read-only, sudo is broken and /nix is baked into ELF. Three limits and a rootless run with mount namespace and chroot
Firefox profile lost after profile-sync-daemon resync
After a Firefox restart the extensions vanished while bookmarks came back. How psd moved the profile into an empty fuse-overlayfs mount and how to restore it