🔍 type — Command Identification Builtin

What is type?

The type builtin tells you exactly what bash will execute when you run a command name. Is it a shell builtin, an alias, a function, or an external binary on the PATH? type answers that question without ambiguity — making it invaluable for debugging, scripting, and understanding your environment.

Unlike which — which only finds external binaries — type sees the full bash command resolution order: aliases → functions → builtins → PATH.

Syntax:
type [OPTIONS] NAME [NAME ...]

type -t NAME    # print type keyword only
type -a NAME    # show ALL matches in order
type -f NAME    # suppress function lookup
type -P NAME    # force PATH search (like which)
type -p NAME    # PATH search, no output if builtin/alias

Command Resolution Order

When you type a command, bash resolves it in this strict order — first match wins:

1. alias

Shell aliases defined with alias command

2. function

Shell functions defined in your session or rc files

3. builtin

Commands built into bash itself — cd, echo, type

4. file

External binaries found on $PATH

5. keyword

Reserved words — if, while, function

Why this matters: If you define a function named ls, it shadows the external /bin/ls entirely. type ls will reveal that immediately. This is the most common source of "why isn't my command working?" confusion.

Examples

1
Basic Type Identification

The fundamental use — find out what a name resolves to:

type ls
type cd
type echo
type if
type grep
Output:
ls is aliased to `ls --color=auto' cd is a shell builtin echo is a shell builtin if is a shell keyword grep is /usr/bin/grep
💡 Instant diagnosis: When a command behaves unexpectedly, type commandname is the first thing to run. An unexpected alias or function shadowing an external binary is a very common culprit.
2
-t Flag — Machine-Readable Type Keyword

The -t flag prints just the type word — perfect for scripting and conditionals:

type -t ls        # alias
type -t cd        # builtin
type -t grep      # file
type -t if        # keyword
type -t myFunc    # function (if defined)
type -t nothing   # (no output, returns 1)
Output (one word per command):
alias builtin file keyword function

Use in scripts to branch on command type:

# Only proceed if the command is an external binary
if [[ "$(type -t rsync)" == "file" ]]; then
    rsync -av /src/ /dst/
else
    echo "rsync not found on PATH" >&2
    exit 1
fi

# Check before calling — works for any type
cmd_exists() {
    [[ -n "$(type -t "$1" 2>/dev/null)" ]]
}

cmd_exists docker && echo "docker available" || echo "docker missing"
💡 Scripting pattern: type -t returns exit code 1 if the name is not found at all — making it clean for boolean tests without parsing output.
3
-a Flag — Show ALL Matches

The -a flag reveals every place a name is defined — aliases, functions, builtins, AND all PATH matches:

type -a echo
type -a ls
type -a python
Output:
echo is a shell builtin echo is /usr/bin/echo ls is aliased to `ls --color=auto' ls is /usr/bin/ls python is /usr/bin/python python is /usr/local/bin/python
Multiple PATH entries: When a command appears more than once on PATH, -a shows all of them in order. The first one is what bash actually runs. This is how you discover version conflicts — e.g., system Python vs. a virtualenv Python.
# Useful one-liner — see full resolution for several commands at once
type -a python python3 pip pip3 2>/dev/null
4
-P Flag — Force PATH Search

-P bypasses aliases and functions and searches PATH directly, like a more honest version of which:

# Even if 'ls' is aliased, -P finds the binary
type -P ls
type -P echo
type -P cd       # returns nothing — cd is a builtin, not on PATH
Output:
/usr/bin/ls /usr/bin/echo
💡 type -P vs which: Both search PATH. But which is an external binary that cannot see bash aliases or functions at all. type -P is a builtin that deliberately skips them. In scripts, prefer type — it's always available, no package needed.
5
Checking for Command Existence in Scripts

The canonical way to check if a command is available before using it:

#!/bin/bash
# Check required tools before starting

require_cmd() {
    local cmd=$1
    if ! type -t "$cmd" &>/dev/null; then
        echo "ERROR: Required command '$cmd' not found." >&2
        exit 1
    fi
}

require_cmd rsync
require_cmd jq
require_cmd aws

echo "All required tools found. Starting..."

Or a softer check with a fallback:

# Use pigz (parallel gzip) if available, fall back to gzip
if type -t pigz &>/dev/null; then
    COMPRESS=pigz
else
    COMPRESS=gzip
fi

tar -cf - /data | $COMPRESS > /backup/data.tar.gz
⚠️ command -v vs type -t: Both are used for existence checks. command -v name is POSIX-portable (works in sh). type -t name is bash-specific but gives you the type keyword too. For bash scripts, either works — type -t is more informative.
6
Revealing Hidden Aliases and Functions

Diagnosing why a command behaves differently than expected:

# Something is wrong with grep — let's see what it really is
type grep
type -a grep

# Is rm really rm? On some systems it's aliased to rm -i
type rm

# Check if someone defined a function shadowing a system command
type sudo
type ssh
Example revealing an alias:
grep is aliased to `grep --color=auto' grep is /usr/bin/grep

To run the real binary, bypassing any alias or function:

# Prefix with backslash to bypass alias
\grep pattern file

# Or use command builtin to bypass alias AND function
command grep pattern file

# Or use the full path from type -P
$(type -P grep) pattern file
7
Identifying Shell Functions

type will show you that something is a function — and display its definition:

# Define a function
mybackup() {
    tar -czf "/backup/$(date +%Y%m%d).tar.gz" "$@"
}

# type shows the full definition
type mybackup
Output:
mybackup is a function mybackup () { tar -czf "/backup/$(date +%Y%m%d).tar.gz" "$@" }
💡 Documenting live environments: type functionname is a quick way to inspect functions defined in your environment without hunting through rc files — especially useful when inheriting someone else's system.
8
Bulk Check — Multiple Commands at Once

type accepts multiple names in one call:

# Check several commands at once
type ls cd grep awk sed find xargs

# Audit your PATH for a list of required tools
REQUIRED=(rsync jq curl wget python3 ansible)
for cmd in "${REQUIRED[@]}"; do
    printf "%-15s %s\n" "$cmd" "$(type -t "$cmd" 2>/dev/null || echo 'NOT FOUND')"
done
Output:
rsync file jq file curl file wget file python3 file ansible NOT FOUND

Quick Reference

CommandWhat it does
type NAMEFull description of what NAME resolves to
type -t NAMEPrint type keyword only: alias, function, builtin, file, keyword
type -a NAMEShow ALL definitions in resolution order
type -P NAMESearch PATH only — skip aliases and functions
type -p NAMEPATH search — silent if not a file
type -f NAMESuppress function lookup
type NAME1 NAME2Check multiple names in one call
type -t NAME &>/dev/nullExistence check for scripts (exit 0/1)

type vs Similar Commands

CommandSees aliases?Sees functions?Sees builtins?Notes
type✅ Yes✅ Yes✅ YesBash builtin — most complete
which❌ No❌ No❌ NoExternal binary — PATH only
command -v✅ Yes✅ Yes✅ YesPOSIX portable — works in sh
whereis❌ No❌ No❌ NoFinds binary, man page, source
whatis❌ No❌ No❌ NoShows man page one-liner only