Skip to content
shellmap

trapRun a handler when the shell receives a signal or exits across all 5 shells

Equivalents in every shell

Bashunix
trap 'cleanup' EXIT

POSIX builtin. Syntax: `trap <action> <signals...>`. Common signals: `EXIT`, `INT` (Ctrl-C), `TERM`, `ERR`, `DEBUG`. The action string is re-evaluated each time the signal fires, so be deliberate about whether `$var` should expand at trap-install time or trap-fire time.

Zshunix
trap 'cleanup' EXIT

Same as bash. Zsh additionally honours the function-name convention: defining `TRAPINT()`, `TRAPEXIT()`, etc. installs a trap for that signal — no `trap` command needed, just the right function name.

Fishunix
trap 'cleanup' EXIT

Fish ships `trap` only as a thin POSIX-compat wrapper around its native event system. The idiomatic form is `function cleanup --on-event fish_exit; ...; end`, or `--on-signal SIGINT` for a specific signal.

PowerShellwindows
try { script } finally { cleanup }

No `trap` for OS signals. PowerShell's `trap { ... }` block catches EXCEPTIONS, not signals — same name as bash, different semantics. For Ctrl-C handling use `[Console]::CancelKeyPress`; for guaranteed cleanup use `try/finally`.

cmd.exewindows
(commands) & cleanup

Cmd has no signal handling and no exit trap. Chaining with `&` (always run next) or `&&` (run on success) is the only sequencing primitive. Pressing Ctrl-C aborts the batch immediately — cleanup steps are skipped.

Worked examples

Run a cleanup function when the script exits

Bash
trap cleanup EXIT
Zsh
trap cleanup EXIT
Fish
function on_exit --on-event fish_exit; cleanup; end
PowerShell
try { run_script } finally { cleanup }

Ignore Ctrl-C inside a critical section

Bash
trap '' INT; critical_task; trap - INT
Zsh
trap '' INT; critical_task; trap - INT
PowerShell
[Console]::TreatControlCAsInput = $true; critical_task; [Console]::TreatControlCAsInput = $false

Log a message whenever any command errors

Bash
trap 'echo "Error at line $LINENO" >&2' ERR
Zsh
trap 'echo "Error at line $LINENO" >&2' ERR
PowerShell
$ErrorActionPreference = 'Stop'; trap { Write-Host "Error: $_" }

Gotchas

  • `trap '' SIGNAL` IGNORES the signal; `trap - SIGNAL` RESETS it to the shell's default handler. The empty-string vs dash distinction is a frequent source of "why isn't my Ctrl-C working?" bugs in script debugging.
  • The `EXIT` trap fires on ANY exit — `exit 0`, `exit 1`, normal end-of-script, and SIGTERM-during-shutdown — but NOT on `SIGKILL` (`kill -9`) and not on power loss. Cleanup code in EXIT is not a substitute for crash-safe state on disk.
  • Bash trap actions run in the SAME shell context, so `local` variables and function state are visible. Inside a subshell `( ... )` traps reset to defaults — handlers defined in the parent will NOT fire for signals delivered to the subshell.
  • PowerShell's `trap { ... }` block is NAMED LIKE bash's but BEHAVES like a global catch — it intercepts exceptions, not OS signals. Porting `trap INT` to a PowerShell `trap { ... }` block silently produces wrong code; use `[Console]::CancelKeyPress` for true signal handling.
  • Fish's `trap` is a POSIX-compat shim — only a small set of signals (notably `EXIT` → `fish_exit`) map cleanly to fish events. For full coverage use `function ... --on-signal SIGTERM ... end` directly instead of the `trap` shim.

WSL & PowerShell Core notes

pwshPowerShell Core has the SAME `trap { ... }`-catches-exceptions semantics on every platform. To handle OS signals on Linux/macOS pwsh, register a `[Console]::CancelKeyPress` handler — bash-style `trap INT` has no direct port. `try/finally` remains the portable cleanup-on-exit primitive in pwsh.
WSLWSL bash receives Linux signals normally, but closing the Windows terminal window may not deliver a clean SIGHUP/EXIT to long-running scripts — cleanup traps can be skipped on abrupt window close. For graceful shutdown, signal the WSL process from outside (`wsl --terminate <distro>`) rather than killing the host terminal.

Related glossary

Common tasks using trap

Related commands