|

Linux CLI 7 🐧 Commands type, which

What are commands?

When you type a command in the shell, several things can happen behind the scenes. The type and which commands help you identify what kind of command you’re running and where it lives on the system.


Overview

ls /usr/bin
type cd
type mv
type cd mv ls
which ls
which blahblah
which -a python
which ls python
CommandDescription
ls /usr/binList all executable files in /usr/bin
type cdShow what kind of command cd is
type mvShow what kind of command mv is
type cd mv lsCheck multiple commands at once
which lsLocate the executable for ls
which blahblahReturns nothing if not found
which -a pythonShow all matches in PATH
which ls pythonCheck multiple commands

What Are Commands?

In Linux, a “command” can be one of several things:

TypeDescriptionExample
External commandAn executable file in /usr/bin, /bin, etc.ls, mv, grep
Shell builtinA command built into the shell itselfcd, echo, pwd
AliasA shortcut for another commandllls -la
Shell functionA custom function defined in the shellmkcd()mkdir + cd
KeywordA reserved word in the shell languageif, for, while

Most commands you use are files in /usr/bin — but not all!


Where Commands Live

ls /usr/bin

This shows all executable files in /usr/bin — but that’s just one of many directories where commands live.

Common directories for executables:

DirectoryPurpose
/binEssential user commands (often symlink to /usr/bin)
/usr/binMost user commands
/sbinSystem administration commands
/usr/sbinNon-essential system commands
/usr/local/binLocally installed software
~/.local/binUser-installed binaries
~/binYour personal scripts

The PATH variable determines where the shell looks for commands:

echo $PATH
# /usr/local/bin:/usr/bin:/bin:/usr/local/sbin:/usr/sbin:/home/kronos/.local/bin

The shell searches these directories in order — the first match wins.


The type Command

The type command identifies what kind of command you’re running.

type cd
type mv
type cd mv ls
CommandDescription
type cdShow what cd is (shell builtin)
type mvShow what mv is (external command)
type cd mv lsCheck multiple commands at once

Examples

$ type cd
cd is a shell builtin

$ type mv
mv is /usr/bin/mv

$ type ls
ls is aliased to `ls --color=auto'

$ type pwd
pwd is a shell builtin

$ type for
for is a shell keyword

Multiple commands at once:

$ type cd mv ls pwd
cd is a shell builtin
mv is /usr/bin/mv
ls is aliased to `ls --color=auto'
pwd is a shell builtin

Exit codes:

$ type cd && echo "found"
cd is a shell builtin
found

$ type nonexistent 2>/dev/null
$ echo $?
1

Output types you’ll see:

OutputMeaning
X is a shell builtinBuilt into the shell
X is /path/to/XExternal executable at that path
X is aliased to 'command'Alias
X is a shell functionFunction defined in shell
X is a shell keywordReserved word
type: X: not foundCommand doesn’t exist

Options for type:

OptionDescription
-aShow all matches (not just the first)
-tShow only the type: alias, keyword, function, builtin, file
-pShow the path (nothing if not a file)
-PForce PATH search (even for builtins)

Examples with options:

# -a shows all matches
$ type -a ls
ls is aliased to `ls --color=auto'
ls is /usr/bin/ls
ls is /bin/ls

# -t shows just the type
$ type -t cd
builtin
$ type -t ls
alias
$ type -t mv
file
$ type -t for
keyword

# -p shows only the path
$ type -p mv
/usr/bin/mv
$ type -p cd
# (empty — cd is not a file)

# -P forces PATH lookup
$ type -P cd
/usr/bin/cd     # (the external cd binary, if it exists)

Why type is useful:

  • Understanding how the shell interprets commands
  • Debugging — know why a command behaves unexpectedly
  • Safety — verify what a command will actually do (e.g., an alias that shadows a real command)
  • Learning — discover which commands are builtins vs external

The which Command

The which command locates the executable file for a given command — but only for external commands.

which ls
which blahblah
which -a python
which ls python
CommandDescription
which lsShow path to ls
which blahblahShow nothing if not found
which -a pythonShow all paths to python
which ls pythonCheck multiple commands

Examples

$ which ls
/usr/bin/ls

$ which mv
/usr/bin/mv

$ which blahblah
# (no output — not found)

$ which ls python
/usr/bin/ls
/usr/bin/python3

The -a option — find all matches:

$ which -a python
/usr/bin/python
/usr/local/bin/python

This is useful when multiple versions of a program are installed — you can see which one will run by default (the first one in $PATH).

Exit codes:

$ which ls
/usr/bin/ls
$ echo $?
0

$ which nonexistent
$ echo $?
1

What which Does NOT Find

which only looks for executable files in $PATH. It will not find:

TypeFound by which?Use instead
Shell builtins❌ Notype
Aliases❌ Notype or alias
Shell functions❌ Notype or declare -f
Keywords❌ Notype

Example:

$ which cd
# (no output — cd is a shell builtin)

$ which ll
# (no output — ll is an alias)

$ type cd
cd is a shell builtin

$ type ll
ll is aliased to `ls -la'

type vs which

Featuretypewhich
Finds builtins✅ Yes❌ No
Finds aliases✅ Yes❌ No
Finds functions✅ Yes❌ No
Finds keywords✅ Yes❌ No
Finds external commands✅ Yes✅ Yes
Shows all matches✅ Yes (-a)✅ Yes (-a)
POSIX standard✅ Yes❌ No (non-standard)
Recommended✅ Yes⚠️ Use with caution

Note: which is not part of POSIX — type is the more portable and reliable choice. On some systems, which may behave differently or not exist.


Complete Example Session

# ============================================
# PART 1: EXPLORING /usr/bin
# ============================================

$ ls /usr/bin | head -20
[
2to3
2to3-3.10
7z
aa-enabled
aa-exec
ab
...

$ ls /usr/bin | wc -l
1876

# ============================================
# PART 2: TYPES OF COMMANDS
# ============================================

# Shell builtin
$ type cd
cd is a shell builtin

$ type pwd
pwd is a shell builtin

$ type echo
echo is a shell builtin

$ type exit
exit is a shell builtin

# External command
$ type mv
mv is /usr/bin/mv

$ type grep
grep is /usr/bin/grep

$ type git
git is /usr/local/bin/git

# Alias
$ type ll
ll is aliased to `ls -la'

$ type la
la is aliased to `ls -A'

# Keyword
$ type for
for is a shell keyword

$ type while
while is a shell keyword

$ type if
if is a shell keyword

# ============================================
# PART 3: TYPE WITH MULTIPLE ARGUMENTS
# ============================================

$ type cd mv ls pwd
cd is a shell builtin
mv is /usr/bin/mv
ls is aliased to `ls --color=auto'
pwd is a shell builtin

$ type -t cd mv ls pwd for
builtin
file
alias
builtin
keyword

# ============================================
# PART 4: TYPE WITH -a (ALL MATCHES)
# ============================================

$ type -a ls
ls is aliased to `ls --color=auto'
ls is /usr/bin/ls
ls is /bin/ls

$ type -a echo
echo is a shell builtin
echo is /usr/bin/echo
echo is /bin/echo

# ============================================
# PART 5: WHICH COMMAND
# ============================================

$ which ls
/usr/bin/ls

$ which mv
/usr/bin/mv

$ which git
/usr/local/bin/git

$ which ls python git
/usr/bin/ls
/usr/bin/python
/usr/local/bin/git

# ============================================
# PART 6: WHICH WITH -a
# ============================================

$ which -a python
/usr/bin/python3.10
/usr/bin/python3
/usr/bin/python

$ which -a node
/usr/bin/node
/usr/local/bin/node

# ============================================
# PART 7: NOT FOUND
# ============================================

$ which blahblah
$ echo $?
1

$ type blahblah
bash: type: blahblah: not found

# ============================================
# PART 8: BUILTINS NOT FOUND BY WHICH
# ============================================

$ which cd
# (no output)

$ which pwd
# (no output)

$ which echo
# (no output on some systems — echo is builtin)

$ type cd
cd is a shell builtin

# ============================================
# PART 9: PRACTICAL — DEBUGGING
# ============================================

# Why does "ls" show colors?
$ type ls
ls is aliased to `ls --color=auto'
# → The alias adds colors

# Which Python will run?
$ which python
/usr/bin/python3.10
# → First in PATH wins

# Is "cd" a real file?
$ type -p cd
# (empty — cd is a builtin, not a file)

Quick Reference

type Options

OptionDescription
(none)Show command type and location
-aShow all matches
-tShow type only
-pShow path only
-PForce PATH lookup
-fSuppress function lookup

which Options

OptionDescription
(none)Show path to executable
-aShow all matches in PATH

Command Types

TypeMeaningExample
BuiltinInside the shellcd, pwd, echo
KeywordShell language keywordif, for, while
AliasShortcutll, la
FunctionCustom shell functionmkcd()
ExternalExecutable filels, mv, grep

Best Practices

Do This:

# Use type for complete information
type cd ls mv

# Use type -a to see all matches
type -a python

# Use type -t for scripting (just the type)
if [ "$(type -t mycmd)" = "function" ]; then
    echo "It's a function"
fi

# Use which to find the default executable
which python

# Use which -a to see all installed versions
which -a node

# Check exit codes for scripts
if which git > /dev/null 2>&1; then
    echo "Git is installed"
fi

Don’t Do This:

# Don't use which to find builtins
which cd                # ❌ Returns nothing

# Don't rely on which for shell behavior
which ls                # ❌ Doesn't show aliases

# Don't use which in portable scripts
# Use "command -v" instead (POSIX):
command -v ls           # ✅ Portable

# Don't assume "which" output is complete
which python            # ⚠️ May not show all versions

The Portable Alternative: command -v

command -v is POSIX-compliant and works everywhere:

$ command -v ls
/usr/bin/ls

$ command -v cd
cd

$ command -v ll
alias ll='ls -la'

$ command -v for
for

Why it’s better:

  • ✅ Works in POSIX shells
  • ✅ Finds builtins, aliases, functions, keywords
  • ✅ Recommended for scripts

Replace which with command -v:

# Instead of:
if which git > /dev/null 2>&1; then

# Use:
if command -v git > /dev/null 2>&1; then

Common Pitfalls

PitfallProblemSolution
Using which for builtinsReturns nothingUse type or command -v
Missing aliases with whichWrong assumptionsUse type -a
Not knowing which Python runsWrong versionwhich -a python
Expecting which to be portableNot POSIXUse command -v
Forgetting PATH orderFirst match winsCheck echo $PATH

Visual: Command Resolution

$ python
   │
   ▼
┌──────────────────────────────────┐
│ 1. Is it an alias?               │
│    → Use alias if yes            │
└──────────────┬───────────────────┘
               │ no
               ▼
┌──────────────────────────────────┐
│ 2. Is it a function?             │
│    → Use function if yes         │
└──────────────┬───────────────────┘
               │ no
               ▼
┌──────────────────────────────────┐
│ 3. Is it a builtin?              │
│    → Use builtin if yes          │
└──────────────┬───────────────────┘
               │ no
               ▼
┌──────────────────────────────────┐
│ 4. Search PATH directories       │
│    → First match wins            │
│    /usr/local/bin → /usr/bin → … │
└──────────────────────────────────┘

Real-World Examples

1. Debug “Why is my command behaving differently?”

$ ll
# Shows long format with colors
$ type ll
ll is aliased to `ls -la'
# → The alias explains the behavior

2. Check Which Python Version Is Default

$ which -a python
/usr/bin/python3.10
/usr/local/bin/python3.11
# → First one wins unless PATH changes

3. Verify a Command Exists in a Script

if command -v git > /dev/null 2>&1; then
    echo "Git is available"
else
    echo "Please install Git"
fi

4. Create an Alias and Verify

$ alias ll='ls -la'
$ type ll
ll is aliased to `ls -la'
$ which ll
# (no output — which doesn't find aliases)

5. Find All Installations of a Program

$ which -a node
/usr/bin/node
/usr/local/bin/node
$ type -a node
node is /usr/local/bin/node
node is /usr/bin/node
# → Same information, different format

Summary

CommandPurposeBest For
typeIdentify command typeComplete command info
whichLocate executable in PATHFinding files
command -vPortable alternativeScripts, POSIX

Key takeaways:

  • Commands come in five types: builtin, keyword, alias, function, external
  • Most commands are external files in /usr/bin and other PATH directories
  • type shows all command types — builtins, aliases, functions, keywords
  • which only finds external executables — not builtins or aliases
  • type -a shows all matches — useful for multiple versions
  • which -a shows all executables in PATH
  • command -v is the portable alternative — use it in scripts

Remember: When you type a command, the shell checks in this order: alias → function → builtin → PATH. Use type to see what’s really happening, and use which (or better, command -v) to find where a program lives. This knowledge is essential for debugging and scripting!


Stop using slow, ad-bloated tool sites! 🤮

🔎 Search “KandZ Tools” on Google to use many professional utilities for free.

KandZ.me is the ultimate minimalist hub for:
✅ Finance (Mortgage, Interest, Inflation)
✅ Tech (Base64, JSON, Dev Suite, IP)
✅ Health (BMI, BMR, TDEE)
✅ Productivity (Timer, Workspace, QR)

⚡️ Fast & Private
🔒 No data leaves your device
💎 100% Free

🔗 Use it now: https://tools.kandz.me
🔖 Bookmark it—you’ll need it later!