opscape

Shell builtins · bash builtin

command

Run a command while skipping functions and aliases of the same name, or check whether a command exists with -v.

command [-pVv] COMMAND [ARGUMENT...]

8 of 8 examples run in Debian 13.7 on 2026-10-31 · manual: bash(1), SHELL BUILTIN COMMANDS

command NAME args runs NAME as a builtin or a program from PATH, ignoring any shell function or alias called NAME. Its main everyday use is inside a wrapper function that has the same name as the command it wraps: without command, the function would call itself forever.

Its second job is detection. command -v NAME prints how NAME would be found (a path for programs, just the name for builtins and functions, the definition for aliases) and returns non-zero when nothing matches. It is the POSIX way to ask "is this installed?", portable to dash and every other sh, unlike which, whose behavior and exit status differ between systems.

command -V gives a human-readable description like type. command -p searches a default PATH that is guaranteed to find the standard utilities, useful when a script cannot trust the caller's PATH.

Examples

Check whether a program is installed

for tool in jq curl kubectl; do
  if command -v "$tool" >/dev/null 2>&1; then
    echo "$tool: found at $(command -v "$tool")"
  else
    echo "$tool: not installed"
  fi
done
output
jq: found at /usr/bin/jq
curl: found at /usr/bin/curl
kubectl: not installed

command -v prints the path and returns 0 when the program exists, and prints nothing and returns 1 when it does not. Redirecting its output keeps the check quiet.

What -v prints for different kinds of names

alias ll='ls -l'
greet() { echo hi; }
command -v grep cd greet ll if
output
/usr/bin/grep
cd
greet
if

A program gives its full path, a builtin, function or keyword just its name. The alias ll prints nothing, because this non-interactive shell does not expand aliases; in a terminal it would print alias ll='ls -l'.

The exit status reflects missing names

command -v kubectl
explain
outputexit 1

(no output)

No output and status 1. In a script, command -v kubectl >/dev/null || { echo "kubectl required" >&2; exit 1; } is the usual guard.

Wrap a command in a function of the same name

grep() { command grep --color=never -n "$@"; }
grep TODO notes.txt src/app.py
output
notes.txt:5:- TODO: write the deploy script
src/app.py:11:    # TODO: read the port from the environment

Inside the function, command grep calls the real program instead of the function itself, so the wrapper adds -n to every call. Without command this function would recurse until bash runs out of stack.

Bypass a function or alias for one call

ls() { echo "(ls is overridden)"; }
ls scripts
command ls scripts
output
(ls is overridden)
backup.sh
greet.sh

The function wins over the program in normal lookup; command ls skips functions and aliases and runs /usr/bin/ls.

Describe a name with -V

command -V ls cd
explain
output
ls is /usr/bin/ls
cd is a shell builtin

-V prints the same wording as type. Use it in the terminal; parse -v in scripts.

Use a safe default PATH with -p

PATH=/nowhere
ls scripts
command -p ls scripts
output
/bin/bash: line 2: ls: command not found
backup.sh
greet.sh

With a broken PATH, ls cannot be found. command -p uses the system's default search path instead and finds it. Handy at the top of scripts run by cron or other tools with a minimal environment.

Keep a failing special builtin from exiting a POSIX shell

command . ./missing.sh
echo "still running, status $?"
. ./missing.sh
echo "never reached"
outputexit 2
/bin/sh: 1: .: cannot open ./missing.sh: No such file
still running, status 2
/bin/sh: 3: .: cannot open ./missing.sh: No such file

In POSIX sh, an error in a special builtin such as ., set or export ends a non-interactive shell. Prefixing it with command turns it into an ordinary failure that the script can handle, which is what happens on the first line.

Common pitfalls

  • Using which in scripts to test for a program: its output and exit codes vary across systems and some versions print "no X in ..." to stdout. command -v X >/dev/null is portable.

  • Forgetting command inside a same-named wrapper function: ls() { ls -F "$@"; } calls itself endlessly and crashes the shell.

  • command -v succeeds for functions and builtins too, so it says a name can run, not that a file exists. Use type -P in bash if you need the path to a binary.

GNU vs BSD and macOS

The examples above ran the GNU/Linux version. These are the differences that matter on macOS and the BSDs (written from their documentation, not run here).

  • command, -v, -V and -p are POSIX and behave the same in bash, dash, zsh and ksh, on Linux and macOS alike. The exact wording of -V differs between shells.

Options worth knowing

A selection, described in our own words. For the full list, see bash(1), SHELL BUILTIN COMMANDS.

OptionWhat it does
-vPrint the path or name that would be used for the command; status 1 if not found.
-VPrint a human-readable description of how the name would be interpreted.
-pSearch a default PATH that finds all standard utilities.

Related