# Shell shell-control-flow ## Conditionals **Conditionals** run commands based on conditions. Use `if` to test exit codes or use `[[ ... ]]` for test expressions. Common operators: `-f` (file exists), `-z` (string empty), `-n` (string non-empty), `=` or `==` (string equal), `-eq` (number equal), `-lt` (less than), `-gt` (greater than). ```bash if [[ -f "$file" ]]; then echo "File exists" elif [[ $count -gt 10 ]]; then echo "Count is greater than 10" else echo "Neither condition true" fi ``` Use `[[ ]]` instead of `[ ]` in Bash—it's more robust and handles quoting better. Use `&&` (AND) and `||` (OR) for one-liners: `cmd1 && cmd2` (run cmd2 if cmd1 succeeds), `cmd1 || cmd2` (run cmd2 if cmd1 fails). ## Loops **Loops** repeat commands. Use `for` to iterate, `while` to repeat while a condition is true, `until` to repeat until a condition is true. ```bash for i in 1 2 3; do echo "Number: $i" done for file in *.txt; do wc -l "$file" done while [[ $count -lt 10 ]]; do echo $count count=$((count + 1)) done ``` Loop control: `break` exits the loop, `continue` skips to the next iteration. ## Exit codes and error handling **Exit codes** (0-255) indicate success or failure. Zero means success, non-zero means failure. Access the last exit code with `$?`. Use `set -e` to exit immediately on error, `set -u` to error on undefined variables, `set -o pipefail` to fail if any command in a pipe fails. ```bash $ command $ echo $? # prints exit code $ command || echo "Failed" # run second command if first fails $ set -e # exit on error $ grep "pattern" file || true # don't exit even if grep fails ``` Always check exit codes and handle errors in scripts. Use `set -e -u -o pipefail` at the top of production scripts.