Skip to content
shellmap

Shell glossary

Definitions for 33 core shell terms — the jargon that shows up in every man page, every Stack Overflow answer, and every error message you’re trying to decode. Cross-linked from command and task pages across the site.

Streams & file descriptors

Every Unix process is born with three open files. Knowing which one you are writing to (or reading from) is the difference between a script that works and a script that silently swallows errors.

stdin(standard input, fd 0)

File descriptor 0 — where a process reads its input.

The default input stream. When you pipe `cat file | grep foo`, `grep`’s stdin is the output of `cat`. By default, stdin is connected to the terminal; closing it or redirecting from `/dev/null` (`cmd </dev/null`) prevents the process from blocking on a read.

stdout(standard output, fd 1)

File descriptor 1 — the normal output stream.

Where regular output goes. Redirect with `>` (overwrite) or `>>` (append): `cmd > out.log`. Piping with `|` connects stdout to the next command’s stdin. Buffered by default when not a terminal (so `cmd | grep` can appear stuck — flush with `stdbuf -oL cmd | grep` on GNU systems).

stderr(standard error, fd 2)

File descriptor 2 — where errors and diagnostics go.

Separate from stdout so error messages don’t pollute parseable output. Redirect with `2>file`; merge into stdout with `2>&1` (order matters: `cmd > out 2>&1` works; `cmd 2>&1 > out` does not). PowerShell’s analog is the error stream accessed via `2>` or `-ErrorVariable`.

file descriptor(fd)

A small integer the kernel gives a process for each open file or stream.

0/1/2 are stdin/stdout/stderr; new files get the lowest free number. The shell can open additional fds: `exec 3<file` opens file for reading on fd 3; `exec 3>&-` closes it. Linux exposes them as `/proc/PID/fd/N` symlinks — useful for inspecting what a running process has open (pair with `lsof -p PID`).

Process identity

Every running program has multiple identifiers beyond its PID. They show up in `ps`, `kill`, `setsid`, job control, and every "why is my Ctrl-C being eaten" debug session.

PID(process ID)

The kernel’s unique number for a single process, assigned at `fork()`.

Stable for the lifetime of the process; recycled (eventually) after exit. Linux `pid_max` caps the value (default 4194304 on 64-bit). Read with `$$` in bash for the current shell, `$BASHPID` in subshells. On Windows, `Get-Process | Select Id` returns the same concept.

PPID(parent PID)

The PID of the process that forked this one.

When a parent dies before its child, the child is re-parented to PID 1 (`init`/`systemd`/`launchd`) — these "orphans" are what makes daemonisation work via double-fork. `ps -o pid,ppid,comm` shows the chain.

PGID(process group ID, process group)

Groups of processes that share signal delivery — the basis for shell job control.

When you press Ctrl-C, the terminal sends `SIGINT` to every process in the foreground PGID, not just the shell. `kill -SIGNAL -PGID` (negative PGID) targets the whole group. Pipelines run as one PGID by default.

SID(session ID)

A higher-level grouping that ties processes to a controlling terminal.

When the terminal hangs up, `SIGHUP` is sent to every process in the session. `setsid cmd` runs `cmd` in a NEW session — no controlling terminal at all — the canonical first step in writing a daemon.

Signals

Signals are tiny inter-process messages. Knowing which ones can be caught, which cannot, and which clean up vs. terminate ungracefully prevents a lot of "service won’t restart" bugs.

SIGTERM(signal 15)

Polite termination request. Default for `kill PID`.

Catchable — the process can install a handler to flush buffers, close connections, write a pid file removal, etc., before exiting. The right default for stopping a service. Docker stops containers with SIGTERM first, then SIGKILL after a 10 s grace period.

SIGKILL(signal 9)

Unconditional termination. The process gets NO chance to clean up.

Cannot be caught, blocked, or ignored — the kernel kills the process directly. Use only when SIGTERM doesn’t work. Side effects: child processes orphaned; open files left in whatever state; on-disk locks may persist. Equivalent on Windows: `taskkill /F`.

SIGINT(signal 2)

The Ctrl-C interrupt. Polite stop, like SIGTERM but specifically from a terminal.

Sent to the foreground PGID when the controlling terminal sees the interrupt character. Catchable; most programs treat it as "stop and exit cleanly". Shells trap it to abort the current command without exiting the shell.

SIGHUP(signal 1)

Hang-up. Originally sent when the modem dropped; now used as a "reload config" convention.

A terminal close sends SIGHUP to every process in the controlling session. `nohup cmd` prevents it (ignores SIGHUP). Many daemons (nginx, sshd, postfix) re-read their config on SIGHUP — `kill -HUP PID` is the canonical "reload, do not restart" gesture.

SIGSTOP / SIGCONT(signal 19, signal 18)

Pause and resume a process at the kernel level.

SIGSTOP cannot be caught — the process is frozen until SIGCONT is delivered. Ctrl-Z sends the catchable SIGTSTP; `kill -STOP PID` sends the uncatchable one. Useful for forcibly pausing a runaway job long enough to inspect it (`gdb -p PID`) without killing.

Exit codes

An exit code is a one-byte unsigned integer (0–255) the parent reads via `wait()`. The shell exposes it as `$?` (bash/zsh/fish) or `$LASTEXITCODE` (PowerShell, for external programs). Conventions matter.

0

Success.

By Unix convention, exit 0 means "everything went fine". Used by `set -e`, `&&`, and CI systems as the only acceptable result.

1

Generic failure.

The catch-all error code. Programs use it when no more specific code applies. `grep` uses 1 specifically to mean "no match" — not really an error, but `set -e` will treat it as one.

2

Usage error or misuse of shell built-in.

Convention for "bad command-line arguments". `bash` uses it for syntax errors in its own input. `find` uses it for invalid expressions.

126

Command found but not executable.

The shell located the binary but the file lacks execute permission, or it’s a directory, or it’s a script with a missing interpreter. `chmod +x` is the usual fix.

127

Command not found.

The shell couldn’t find the command at all — typo, missing from `$PATH`, or executed inside a context (sudo, cron, systemd) with a different PATH than your interactive shell.

128 + N

Process killed by signal N.

When a process dies from signal N, the shell reports `128 + N`. 130 = killed by SIGINT (Ctrl-C). 137 = killed by SIGKILL (often OOM-killer). 143 = killed by SIGTERM. Useful for distinguishing "user pressed Ctrl-C" from "exited with code 1".

130

Killed by SIGINT (Ctrl-C).

The number you see when a user aborts an interactive command. CI runners interpret this as "manually cancelled", different from a real test failure.

137

Killed by SIGKILL — usually OOM.

A process that exits 137 was forcibly terminated. The Linux Out-Of-Memory killer leaves this fingerprint; `dmesg | grep -i kill` confirms. In Kubernetes, exit 137 in pod logs is the classic "memory limit exceeded" signal.

Environment variables

Each process gets its own copy of the parent’s environment at `fork()`. Mutating it in a child does not affect the parent — the asymmetry trips up almost every new shell user.

environment variable

A `KEY=value` pair attached to a process, inherited by children.

Set with `export NAME=value` (bash/zsh), `set -gx NAME value` (fish), or `$env:NAME = "value"` (PowerShell). Without `export`/`-gx`, the variable is local to the current shell and not visible to programs it spawns.

$PATH

Colon-separated list (semicolon on Windows) of directories the shell searches for executables.

Order matters — the first match wins. `which cmd` / `command -v cmd` (Unix) and `Get-Command cmd` / `where.exe cmd` (Windows) reveal which file would run. `sudo` deliberately rewrites PATH to a "safe" set; commands that "work as me but not under sudo" usually live outside that safe set.

$HOME

The user’s home directory. `~` is shorthand.

Set by login; most config files live here (`~/.bashrc`, `~/.config/...`). Inside a Docker container running as root, $HOME is usually `/root` regardless of the running user — adjust deliberately if your image runs as a non-root user.

$PWD

The current working directory.

Updated by `cd`; `pwd` prints it. The kernel actually tracks `cwd` (via `getcwd()`); `$PWD` is the shell’s logical record (which can differ when symlinks are involved). `cd -P` follows symlinks physically and resyncs them.

$IFS(Internal Field Separator)

Characters bash uses to split unquoted variable expansions into words.

Default: space, tab, newline. Setting `IFS=$'\n'` while reading a file makes `for line in $(cat f)` iterate line-by-line. The single biggest source of "shell injection through filename" bugs — always quote variables (`"$var"`) unless you specifically want splitting.

Terminals & shell modes

A "shell" is a program; a "terminal" is the thing it talks to. They’re commonly conflated. Different combinations have different rules about job control, signals, and which startup files get sourced.

tty

A real, physical terminal device — or the kernel’s emulation of one.

Each interactive shell is attached to a tty (`/dev/tty1`, `/dev/pts/0`, etc.). `tty` (the command) prints the path of the current one. Without a tty, programs may behave differently — `git` won’t prompt for credentials, `less` exits immediately, color output is suppressed by default.

pty(pseudo-terminal)

A software-emulated tty pair used by terminal emulators, SSH, and tmux.

A pty has two ends: the "master" (read by the terminal emulator) and the "slave" (where the shell or program runs, looking like a real tty). `ssh -t` forces pty allocation when the remote command needs one. `tmux` and `screen` create their own ptys so processes survive disconnect.

foreground process

The process group currently attached to the terminal’s input and signals.

Only one PGID at a time. When in foreground, Ctrl-C and Ctrl-Z reach the process; stdout is connected to the terminal. `fg %1` brings job 1 back to foreground.

background process

A process started with trailing `&`, detached from terminal input.

Still owned by the shell’s session — exits when the shell exits unless `disown`ed or `nohup`ped. `jobs` lists them; `bg %N` resumes a stopped job in the background. Output still goes to the terminal unless redirected.

daemon

A long-running background process detached from any controlling terminal.

Traditional daemonisation: fork twice, `setsid`, `chdir("/")`, `umask(0)`, close fds 0/1/2. Modern Linux uses `systemd` instead — write a `.service` unit and let `systemd` manage the lifecycle. macOS: `launchd` plists. Windows: services via `sc.exe` or NSSM.

login shell

The shell you get at the start of a session (e.g., after SSH or a terminal login).

Bash sources `/etc/profile` and the first existing of `~/.bash_profile`, `~/.bash_login`, `~/.profile`. Zsh sources `/etc/zprofile` and `~/.zprofile`. The distinction matters because env vars set in `.bashrc` won’t be present in non-interactive sub-shells if they’re defined for login-only.

interactive shell

A shell that reads commands from a terminal, vs. running a script.

Bash sources `~/.bashrc` for interactive non-login shells. The `$PS1` prompt and `$-` containing `i` are the runtime signals. Scripts run by bash do NOT source `~/.bashrc` by default — explain "my alias works in the terminal but not in this script".

Keep reading