exit-codes-traps.md

reference

← Back to skill

Content hash: 595c4c095bc3d4d6647cbd2612f2442ce02f57a13b4047a778533b7b64c1e651
# Exit Codes and Trap Patterns

## Exit code conventions

| Code | Meaning | When to use |
|------|---------|-------------|
| 0    | Success | Normal exit |
| 1    | General error | Catch-all for unexpected failures |
| 2    | Misuse | Wrong arguments, invalid flags |
| 126  | Not executable | Permission denied |
| 127  | Not found | Missing command/dependency |
| 130  | Ctrl+C | Script interrupted by SIGINT |

## Best trap patterns

```bash
# Clean up temp files on exit (normal or error)
TMPDIR=$(mktemp -d)
trap 'rm -rf "$TMPDIR"' EXIT

# Chain traps for multiple signals
trap 'echo "Interrupted"; exit 130' INT TERM
trap 'echo "Cleaning up..."; kill $PID 2>/dev/null' EXIT
```

## `set -e` gotchas

- `set -e` does NOT trigger inside `if`, `while`, `||`, or `&&` — that's by design
- Use explicit `|| die` chains when you need guaranteed exit:
  ```bash
  result=$(dangerous_command) || die "Failed"
  ```
- In functions called from conditions, errors are silenced — extract the call:
  ```bash
  ok=$(my_func)
  if [[ "$ok" == "ready" ]]; then ...
  ```

## `set -u` workarounds

```bash
# Check if a variable is set without triggering -u
if [[ -n "${VAR+x}" ]]; then
    echo "VAR is set to '$VAR'"
fi

# Provide defaults
OUTPUT="${1:-/tmp/default}"
```