The shell's switch
case "$1" in
start) ./serve.sh & ;;
stop) pkill -f serve.sh ;;
status) pgrep -fa serve.sh ;;
*) echo "usage: $0 {start|stop|status}"; exit 2 ;;
esacEach branch ends with ;;. Patterns are glob-style (*, ?, [abc]) and the first match wins. *) at the bottom is the default.
Multiple patterns per branch
case "$ext" in
jpg|jpeg|png|gif|webp) echo image ;;
mp4|mov|webm) echo video ;;
*.bak|*~|*.tmp) echo trash ;;
*) echo other ;;
esacfallthrough (bash 4+, zsh)
End a branch with ;;& to continue testing the next patterns, or ;& to fall through to the next branch's body. Rare but useful.
When case beats if
If you find yourself writing more than two elifs with string equality, switch to case. It's flatter, easier to read, and faster on large alternatives. Most CLI dispatch in shell scripts (start|stop|status|reload) is a case statement.
Patterns are not regular expressions
case uses shell patterns. Keep validation that needs richer syntax inside an explicit command rather than guessing that regex operators carry over.
Dispatch does not validate the target
A branch that runs pkill -f can still match unrelated processes. Prefer a service identity or a verified PID, and always include a rejecting default branch.
A rejecting default completes the interface
A case statement without a default can silently accept an unknown action by doing nothing. Print valid choices and return nonzero so callers can distinguish rejection from success.