ShBash · Lesson 3 of 8

Control Flow

Bash conditionals look strange at first. The [ ... ] is actually a command (test). The spaces inside are required. Yes, really.

Bash
#!/bin/bash

# if / elif / else
age=20
if [ "$age" -ge 18 ]; then
    echo "Adult"
elif [ "$age" -ge 13 ]; then
    echo "Teenager"
else
    echo "Child"
fi

# Numeric comparisons (use -eq -ne -lt -le -gt -ge, NOT == < >)
x=10
if [ "$x" -eq 10 ]; then echo "equal to 10"; fi
if [ "$x" -gt 5 ]; then  echo "greater than 5"; fi
if [ "$x" -lt 20 ]; then echo "less than 20"; fi

# String comparisons
name="Alice"
if [ "$name" = "Alice" ]; then echo "It's Alice!"; fi
if [ -z "$name" ]; then echo "Empty string"; fi     # -z: zero length
if [ -n "$name" ]; then echo "Non-empty string"; fi # -n: non-zero length

# File tests
if [ -f "script.sh" ]; then echo "File exists"; fi
if [ -d "/tmp" ]; then echo "Directory exists"; fi
if [ -e "anything" ]; then echo "Path exists"; fi
if [ -r "file.txt" ]; then echo "Readable"; fi
if [ -x "script.sh" ]; then echo "Executable"; fi

# Combine conditions
if [ "$age" -ge 18 ] && [ "$name" = "Alice" ]; then
    echo "Adult Alice"
fi

# [[ ]] is more powerful (bash-specific, but preferred)
if [[ "$name" == Ali* ]]; then   # pattern matching!
    echo "Name starts with Ali"
fi
Bash
#!/bin/bash

# for loop — over a list
for fruit in apple banana cherry; do
    echo "I like $fruit"
done

# for loop — with range
for i in {1..5}; do
    echo "Count: $i"
done

# for loop — C-style
for ((i=0; i<5; i++)); do
    echo "i = $i"
done

# for loop — over files
for file in *.sh; do
    echo "Shell script: $file"
done

# for loop — over command output
for user in $(cut -d: -f1 /etc/passwd | head -5); do
    echo "User: $user"
done

# while loop
count=0
while [ "$count" -lt 5 ]; do
    echo "count: $count"
    ((count++))
done

# read lines from a file
while IFS= read -r line; do
    echo "Line: $line"
done < "data.txt"

# until loop — opposite of while
n=10
until [ "$n" -le 0 ]; do
    echo "$n"
    ((n -= 3))
done