# if, elif, case and Short-Circuit Operators — Bash / Shell Scripting

Source: https://www.skillbyai.com/en/bash/c-branches

> Branch with if, case, && and ||.

## Choosing a path

An **`if`** statement runs a command list and branches on its status: `if cmd; then ...; elif other; then ...; else ...; fi`. Any command can be a condition, not just tests: `if grep -q ERROR app.log; then` is idiomatic. **`case`** matches a value against glob patterns and is cleaner than long `if/elif` chains for things like command-line subcommands or file types: each branch ends with `;;`, patterns can be combined with `|`, and `*)` is the default. **Short-circuit operators** chain commands: `cmd1 && cmd2` runs `cmd2` only if `cmd1` succeeds; `cmd1 || cmd2` runs `cmd2` only if `cmd1` fails, which is handy for `mkdir -p dir || exit 1` or `command -v jq >/dev/null || die "jq required"`. Avoid the `a && b || c` idiom as an if/else replacement: if `b` fails, `c` runs too. Use a real `if` when you mean if/else.

## A subcommand dispatcher with case

Typical structure of a small CLI tool.

```bash
#!/usr/bin/env bash
set -euo pipefail

usage() { printf 'usage: %s {start|stop|status} [service]\n' "$0" >&2; exit 2; }

cmd="${1:-}"
service="${2:-web}"

case "$cmd" in
    start)        echo "starting $service" ;;
    stop|halt)    echo "stopping $service" ;;
    status)
        if systemctl is-active --quiet "$service"; then
            echo "$service is running"
        else
            echo "$service is stopped"
        fi
        ;;
    -h|--help|"") usage ;;
    *)            echo "unknown command: $cmd" >&2; usage ;;
esac
```

## A railway points switch

`case` is a set of railway points: the train (value) is routed down exactly one track depending on its destination board (pattern), with a siding (`*)`) for anything unexpected.

**Quiz:** In `cmd1 || cmd2`, when does cmd2 run?

- [ ] Always
- [ ] Only if cmd1 succeeds
- [ ] Never
- [x] Only if cmd1 fails

*Answer:* Only if cmd1 fails. || runs the right-hand command only when the left-hand one returns a non-zero status.
