|

Linux CLI 62 🐧 loops in shell scripts

#!/bin/bash

# Initialize a counter variable
count=1

# While count is less than or equal to 5, print the current value and increment it
while [ $count -le 5 ]; do
    echo "Count is $count"
    count=$((count + 1))
done

count=1

# While count is less than or equal to 5, print the current value and increment it
while [ $count -le 5 ]; do
    if [ $count -eq 3 ]; then
        echo "Breaking loop at count 3."
        break
    fi
    echo "Count is $count"
    count=$((count + 1))
done

# Initialize a counter variable
count=1

# While count is less than or equal to 5, print the current value and increment it
while [ $count -le 5 ]; do
    if [ $count -eq 3 ]; then
        echo "Skipping count 3."
        count=$((count + 1))
        continue
    fi
    echo "Count is $count"
    count=$((count + 1))
done

until [ "$user_input" == "exit" ]; do
    echo "Please enter your name (or type 'exit' to quit):"
    read user_input

    if [ -z "$user_input" ]; then
        echo "You did not provide any input. Please try again."
    elif [ "$user_input" != "exit" ]; then
        echo "Hello, $user_input!"
    fi
done

Loops are how a script repeats work. Instead of writing the same command ten times, you write it once and let the loop run it ten times. Bash gives you two main conditional loops — while and until — plus for for iterating over lists. This chapter covers while and until; for comes next.

Key point: A while loop runs as long as its condition is true. An until loop runs until its condition becomes true. They’re mirror images — the same logic, opposite framing. Both check the condition before each iteration, so it’s possible for the body to never run.


a – while loop in shell scripts

A while loop executes its block of commands as long as the given condition remains true.

Syntax:

while [ condition ]; do
    # Commands to execute
done

How it works:

  1. [ condition ] is evaluated before each iteration.
  2. If true, the commands inside the loop run.
  3. Once the commands finish, the condition is re-evaluated.
  4. This continues until the condition becomes false.

Basic example — count to 5:

#!/bin/bash

count=1

while [ $count -le 5 ]; do
    echo "Count is $count"
    count=$((count + 1))
done
[ Count is 1 ]
[ Count is 2 ]
[ Count is 3 ]
[ Count is 4 ]
[ Count is 5 ]

Let’s break it down:

  • count=1 → initialize
  • while [ $count -le 5 ] → loop while count is less than or equal to 5
  • echo "Count is $count" → print the current value
  • count=$((count + 1)) → increment
  • done → end of loop

⚠️ Warning: If you forget to increment, the loop runs forever — an infinite loop. Always make sure something inside the loop moves the condition toward false.

The break command — exit the loop early:

count=1

while [ $count -le 5 ]; do
    if [ $count -eq 3 ]; then
        echo "Breaking loop at count 3."
        break
    fi
    echo "Count is $count"
    count=$((count + 1))
done
[ Count is 1 ]
[ Count is 2 ]
[ Breaking loop at count 3. ]

break immediately exits the loop, even though the condition was still true. Control passes to the first command after done.

The continue command — skip to the next iteration:

count=1

while [ $count -le 5 ]; do
    if [ $count -eq 3 ]; then
        echo "Skipping count 3."
        count=$((count + 1))
        continue
    fi
    echo "Count is $count"
    count=$((count + 1))
done
[ Count is 1 ]
[ Count is 2 ]
[ Skipping count 3. ]
[ Count is 4 ]
[ Count is 5 ]

continue skips the rest of the current iteration and jumps back to the condition check. In this example, when count is 3, the loop prints “Skipping”, increments, and moves on — the echo "Count is $count" is never reached for that iteration.

Note: In a while loop, if you use continue, make sure you increment before continuing — otherwise you’ll be stuck on the same value forever.

The classic infinite loop:

while true; do
    echo "Running..."
    sleep 1
done

true is a command that always returns 0 (success). The loop runs until you kill it with Ctrl+C or hit a break.

Reading input with a while loop:

while read -r line; do
    echo "Line: $line"
done < file.txt

This reads a file line by line. The loop ends when read returns non-zero — which it does at end-of-file.

A menu with a while loop:

while true; do
    echo "1) Date"
    echo "2) Uptime"
    echo "3) Quit"
    read -p "Choice: " choice
    case "$choice" in
        1) date ;;
        2) uptime ;;
        3) break ;;
        *) echo "Invalid" ;;
    esac
done

The loop runs forever until the user chooses “Quit”, which triggers break.

More while loop examples:

# Countdown
count=5
while [ $count -gt 0 ]; do
    echo "$count"
    count=$((count - 1))
done
echo "Liftoff!"
# Sum numbers from 1 to 10
sum=0
n=1
while [ $n -le 10 ]; do
    sum=$((sum + n))
    n=$((n + 1))
done
echo "Sum: $sum"
[ Sum: 55 ]
# Retry until success
attempts=0
until curl -s https://example.com > /dev/null; do
    attempts=$((attempts + 1))
    if [ $attempts -ge 5 ]; then
        echo "Giving up after 5 attempts"
        break
    fi
    sleep 1
done

Nested while loops:

i=1
while [ $i -le 3 ]; do
    j=1
    while [ $j -le 3 ]; do
        echo "$i x $j = $((i * j))"
        j=$((j + 1))
    done
    i=$((i + 1))
done
[ 1 x 1 = 1 ]
[ 1 x 2 = 2 ]
[ 1 x 3 = 3 ]
[ 2 x 1 = 2 ]
[ 2 x 2 = 4 ]
[ 2 x 3 = 6 ]
[ 3 x 1 = 3 ]
[ 3 x 2 = 6 ]
[ 3 x 3 = 9 ]

break with a level (bash 4+):

while true; do
    while true; do
        break 2    # breaks out of BOTH loops
    done
done

break 2 exits two levels of loops. continue 2 similarly continues the outer loop.


b – until loop in shell scripts

An until loop is a control flow statement that repeatedly executes a block of code as long as a specified condition evaluates to false. Once the condition becomes true, the loop terminates.

Syntax:

until [ condition ]; do
    # Commands to execute
done

[ condition ] is the condition that must become true for the loop to exit.

Example — interactive until loop:

until [ "$user_input" == "exit" ]; do
    echo "Please enter your name (or type 'exit' to quit):"
    read user_input

    if [ -z "$user_input" ]; then
        echo "You did not provide any input. Please try again."
    elif [ "$user_input" != "exit" ]; then
        echo "Hello, $user_input!"
    fi
done
[ Please enter your name (or type 'exit' to quit): ]
Alice
[ Hello, Alice! ]
[ Please enter your name (or type 'exit' to quit): ]
Bob
[ Hello, Bob! ]
[ Please enter your name (or type 'exit' to quit): ]
(empty)
[ You did not provide any input. Please try again. ]
[ Please enter your name (or type 'exit' to quit): ]
exit
# loop ends

The loop continues until the user types exit. until reads naturally here: “until the user types exit, keep asking.”

Simple countdown with until:

count=5

until [ $count -eq 0 ]; do
    echo "$count"
    count=$((count - 1))
done
echo "Done!"
[ 5 ]
[ 4 ]
[ 3 ]
[ 2 ]
[ 1 ]
[ Done! ]

Wait for a file to appear:

until [ -f /tmp/ready ]; do
    echo "Waiting for /tmp/ready..."
    sleep 1
done
echo "File appeared!"

Wait for a service to be reachable:

until curl -s http://localhost:8080/health > /dev/null; do
    echo "Service not ready, retrying..."
    sleep 2
done
echo "Service is up!"

while vs until:

Aspectwhileuntil
Runs whileCondition is trueCondition is false
Stops whenCondition becomes falseCondition becomes true
Typical useKnown iteration countWaiting for an event
Reads naturally as“While X, do Y”“Until X, do Y”

The same loop written both ways:

# while version
count=1
while [ $count -le 5 ]; do
    echo "$count"
    count=$((count + 1))
done

# until version — same output
count=1
until [ $count -gt 5 ]; do
    echo "$count"
    count=$((count + 1))
done

Both print 1 through 5. The until version flips the condition: “until count is greater than 5″ is the same as “while count is less than or equal to 5.”

Which should you use?

  • Use while when you’re looping while something is true
  • Use until when you’re looping until something happens

until reads more naturally for polling or waiting:

until ping -c1 server > /dev/null 2>&1; do
    sleep 1
done
echo "Server is reachable"

while reads more naturally for iteration or counters:

while [ $i -lt 10 ]; do
    echo "$i"
    i=$((i + 1))
done

break and continue work the same:

count=1
until [ $count -gt 5 ]; do
    if [ $count -eq 3 ]; then
        count=$((count + 1))
        continue
    fi
    echo "$count"
    count=$((count + 1))
done
[ 1 ]
[ 2 ]
[ 4 ]
[ 5 ]

Infinite until loop (rarely useful):

until false; do
    echo "This runs forever"
    sleep 1
done

false always returns 1 (failure), so the loop never exits — same as while true.

Real-world until patterns:

# Wait for a process to finish
until ! pgrep -x myservice > /dev/null; do
    echo "Still running..."
    sleep 5
done
echo "Process finished"
# Retry a download up to 5 times
attempt=0
until curl -sO https://example.com/file.zip || [ $attempt -ge 5 ]; do
    attempt=$((attempt + 1))
    echo "Retry $attempt..."
    sleep 2
done
# Wait for user confirmation
until [ "$confirm" = "yes" ]; do
    read -p "Type 'yes' to continue: " confirm
done
echo "Proceeding..."

Complete Example Session

# ============================================
# PART 1: BASIC WHILE LOOP
# ============================================

$ cat > count.sh << 'EOF'
#!/bin/bash
count=1
while [ $count -le 5 ]; do
    echo "Count is $count"
    count=$((count + 1))
done
EOF
$ chmod +x count.sh
$ ./count.sh
[ Count is 1 ]
[ Count is 2 ]
[ Count is 3 ]
[ Count is 4 ]
[ Count is 5 ]

# ============================================
# PART 2: BREAK
# ============================================

$ cat > break.sh << 'EOF'
#!/bin/bash
count=1
while [ $count -le 5 ]; do
    if [ $count -eq 3 ]; then
        echo "Breaking loop at count 3."
        break
    fi
    echo "Count is $count"
    count=$((count + 1))
done
EOF
$ chmod +x break.sh
$ ./break.sh
[ Count is 1 ]
[ Count is 2 ]
[ Breaking loop at count 3. ]

# ============================================
# PART 3: CONTINUE
# ============================================

$ cat > continue.sh << 'EOF'
#!/bin/bash
count=1
while [ $count -le 5 ]; do
    if [ $count -eq 3 ]; then
        echo "Skipping count 3."
        count=$((count + 1))
        continue
    fi
    echo "Count is $count"
    count=$((count + 1))
done
EOF
$ chmod +x continue.sh
$ ./continue.sh
[ Count is 1 ]
[ Count is 2 ]
[ Skipping count 3. ]
[ Count is 4 ]
[ Count is 5 ]

# ============================================
# PART 4: COUNTDOWN
# ============================================

$ count=5
$ while [ $count -gt 0 ]; do
>     echo "$count"
>     count=$((count - 1))
> done
[ 5 ]
[ 4 ]
[ 3 ]
[ 2 ]
[ 1 ]

# ============================================
# PART 5: SUM 1 TO 10
# ============================================

$ sum=0
$ n=1
$ while [ $n -le 10 ]; do
>     sum=$((sum + n))
>     n=$((n + 1))
> done
$ echo "Sum: $sum"
[ Sum: 55 ]

# ============================================
# PART 6: READ FILE LINE BY LINE
# ============================================

$ printf "line1\nline2\nline3\n" > file.txt
$ while IFS= read -r line; do
>     echo "Got: $line"
> done < file.txt
[ Got: line1 ]
[ Got: line2 ]
[ Got: line3 ]

# ============================================
# PART 7: NESTED LOOPS
# ============================================

$ i=1
$ while [ $i -le 3 ]; do
>     j=1
>     while [ $j -le 3 ]; do
>         echo "$i x $j = $((i * j))"
>         j=$((j + 1))
>     done
>     i=$((i + 1))
> done
[ 1 x 1 = 1 ]
[ 1 x 2 = 2 ]
[ 1 x 3 = 3 ]
[ 2 x 1 = 2 ]
[ 2 x 2 = 4 ]
[ 2 x 3 = 6 ]
[ 3 x 1 = 3 ]
[ 3 x 2 = 6 ]
[ 3 x 3 = 9 ]

# ============================================
# PART 8: INFINITE LOOP WITH BREAK
# ============================================

$ count=0
$ while true; do
>     count=$((count + 1))
>     echo "Iteration $count"
>     if [ $count -ge 3 ]; then
>         break
>     fi
> done
[ Iteration 1 ]
[ Iteration 2 ]
[ Iteration 3 ]

# ============================================
# PART 9: BASIC UNTIL LOOP
# ============================================

$ count=5
$ until [ $count -eq 0 ]; do
>     echo "$count"
>     count=$((count - 1))
> done
[ 5 ]
[ 4 ]
[ 3 ]
[ 2 ]
[ 1 ]

# ============================================
# PART 10: UNTIL WITH USER INPUT
# ============================================

$ cat > ask.sh << 'EOF'
#!/bin/bash
until [ "$user_input" == "exit" ]; do
    echo "Please enter your name (or type 'exit' to quit):"
    read user_input

    if [ -z "$user_input" ]; then
        echo "You did not provide any input. Please try again."
    elif [ "$user_input" != "exit" ]; then
        echo "Hello, $user_input!"
    fi
done
EOF
$ chmod +x ask.sh
$ ./ask.sh
[ Please enter your name (or type 'exit' to quit): ]
Alice
[ Hello, Alice! ]
[ Please enter your name (or type 'exit' to quit): ]
exit

# ============================================
# PART 11: WAIT FOR A FILE
# ============================================

$ (sleep 2; touch /tmp/ready) &
$ until [ -f /tmp/ready ]; do
>     echo "Waiting..."
>     sleep 1
> done
$ echo "File appeared!"
[ Waiting... ]
[ Waiting... ]
[ File appeared! ]

# ============================================
# PART 12: WHILE VS UNTIL
# ============================================

# Same loop, both forms
$ count=1
$ while [ $count -le 3 ]; do echo "$count"; count=$((count+1)); done
[ 1 ]
[ 2 ]
[ 3 ]

$ count=1
$ until [ $count -gt 3 ]; do echo "$count"; count=$((count+1)); done
[ 1 ]
[ 2 ]
[ 3 ]

# ============================================
# PART 13: MENU
# ============================================

$ cat > menu.sh << 'EOF'
#!/bin/bash
while true; do
    echo "1) Date"
    echo "2) Uptime"
    echo "3) Quit"
    read -p "Choice: " c
    case "$c" in
        1) date ;;
        2) uptime ;;
        3) break ;;
        *) echo "Invalid" ;;
    esac
done
EOF
$ chmod +x menu.sh
$ ./menu.sh
[ 1) Date ]
[ 2) Uptime ]
[ 3) Quit ]
Choice: 1
[ Mon Jan 15 10:00:00 UTC 2024 ]
[ 1) Date ]
[ 2) Uptime ]
[ 3) Quit ]
Choice: 3

# ============================================
# PART 14: RETRY UNTIL SUCCESS
# ============================================

$ attempts=0
$ until curl -s https://example.com > /dev/null; do
>     attempts=$((attempts + 1))
>     if [ $attempts -ge 3 ]; then
>         echo "Giving up"
>         break
>     fi
>     echo "Retry $attempts..."
>     sleep 1
> done

# ============================================
# PART 15: FULL SCRIPT
# ============================================

$ cat > loops.sh << 'EOF'
#!/bin/bash

count=1
while [ $count -le 5 ]; do
    echo "Count is $count"
    count=$((count + 1))
done

count=1
while [ $count -le 5 ]; do
    if [ $count -eq 3 ]; then
        echo "Breaking loop at count 3."
        break
    fi
    echo "Count is $count"
    count=$((count + 1))
done

count=1
while [ $count -le 5 ]; do
    if [ $count -eq 3 ]; then
        echo "Skipping count 3."
        count=$((count + 1))
        continue
    fi
    echo "Count is $count"
    count=$((count + 1))
done

until [ "$user_input" == "exit" ]; do
    echo "Please enter your name (or type 'exit' to quit):"
    read user_input

    if [ -z "$user_input" ]; then
        echo "You did not provide any input. Please try again."
    elif [ "$user_input" != "exit" ]; then
        echo "Hello, $user_input!"
    fi
done
EOF
$ chmod +x loops.sh
$ ./loops.sh
[ Count is 1 ]
[ Count is 2 ]
[ Count is 3 ]
[ Count is 4 ]
[ Count is 5 ]
[ Count is 1 ]
[ Count is 2 ]
[ Breaking loop at count 3. ]
[ Count is 1 ]
[ Count is 2 ]
[ Skipping count 3. ]
[ Count is 4 ]
[ Count is 5 ]
[ Please enter your name (or type 'exit' to quit): ]
Alice
[ Hello, Alice! ]
[ Please enter your name (or type 'exit' to quit): ]
exit

Quick Reference

while Loop

CommandPurpose
while [ cond ]; do ... doneLoop while true
while true; do ... doneInfinite loop
while read -r line; do ... done < fileRead file line by line
while IFS= read -r linePreserve whitespace

until Loop

CommandPurpose
until [ cond ]; do ... doneLoop until true
until [ -f file ]; do sleep 1; doneWait for file
until curl URL; do sleep 1; doneWait for service

Loop Control

CommandPurpose
breakExit the loop
continueSkip to next iteration
break 2Exit 2 levels (bash 4+)
continue 2Continue outer loop

Comparison Operators in Conditions

OperatorMeaning
-eqEqual
-neNot equal
-ltLess than
-leLess or equal
-gtGreater than
-geGreater or equal

while vs until

Aspectwhileuntil
Runs whileTrueFalse
Stops whenFalseTrue
Use forIterationWaiting
Reads as“While X, do Y”“Until X, do Y”

Common Patterns

PatternPurpose
while [ $i -le N ]Count up
while [ $i -gt 0 ]Count down
while true + breakMenu, retry
until [ -f file ]Wait for file
while read -r lineProcess file
until curl URLWait for service

Best Practices

✅ Do This:

# Always change the condition variable
while [ $i -le 5 ]; do
    echo "$i"
    i=$((i + 1))                    # ✅
done

# Use break for early exit
while true; do
    read -p "> " cmd
    [ "$cmd" = "quit" ] && break
done                                # ✅

# Use IFS= read -r for files
while IFS= read -r line; do
    echo "$line"
done < file.txt                     # ✅

# Increment before continue in while loops
while [ $i -le 5 ]; do
    if [ $i -eq 3 ]; then
        i=$((i + 1))
        continue
    fi
    echo "$i"
    i=$((i + 1))
done                                # ✅

# Use until for waiting
until [ -f /tmp/ready ]; do
    sleep 1
done                                # ✅

# Add a safety limit to infinite loops
attempts=0
while true; do
    attempts=$((attempts + 1))
    [ $attempts -ge 10 ] && break
done                                # ✅

❌ Don’t Do This:

# Don't forget to increment
while [ $i -le 5 ]; do
    echo "$i"
done                                # ❌ infinite loop

# Don't continue without incrementing
while [ $i -le 5 ]; do
    if [ $i -eq 3 ]; then
        continue                    # ❌ stuck on 3 forever
    fi
    i=$((i + 1))
done

# Don't read files without -r
while read line; do ...; done < f   # ⚠️  backslashes eaten

# Don't use while read with a pipe if you need variables after
cat f | while read line; do
    LAST="$line"
done
echo "$LAST"                        # ❌ empty — subshell

# Don't forget to quote in conditions
while [ $name = "exit" ]; do        # ⚠️  breaks if empty
while [ "$name" = "exit" ]; do      # ✅

# Don't use while for a known iteration count
i=0
while [ $i -lt 10 ]; do ...; done   # ⚠️  for loop is cleaner

Common Pitfalls

PitfallProblemSolution
Forgot incrementInfinite loopAlways increment
continue before incrementStuck loopIncrement first
read without -rBackslashes eatenread -r
Pipe subshellVariables lostUse redirect < file
Unquoted variableBreaks on emptyQuote it
No break in menuCan’t exitAdd a quit option
No safety limitRuns foreverAdd attempt counter
Wrong comparisonNever enters/exitsCheck -lt vs -gt

Real-World Examples

1. Count to 5

#!/bin/bash
count=1
while [ $count -le 5 ]; do
    echo "Count is $count"
    count=$((count + 1))
done
[ Count is 1 ]
[ Count is 2 ]
[ Count is 3 ]
[ Count is 4 ]
[ Count is 5 ]

2. Break at 3

#!/bin/bash
count=1
while [ $count -le 5 ]; do
    if [ $count -eq 3 ]; then
        echo "Breaking loop at count 3."
        break
    fi
    echo "Count is $count"
    count=$((count + 1))
done
[ Count is 1 ]
[ Count is 2 ]
[ Breaking loop at count 3. ]

3. Skip 3

#!/bin/bash
count=1
while [ $count -le 5 ]; do
    if [ $count -eq 3 ]; then
        echo "Skipping count 3."
        count=$((count + 1))
        continue
    fi
    echo "Count is $count"
    count=$((count + 1))
done
[ Count is 1 ]
[ Count is 2 ]
[ Skipping count 3. ]
[ Count is 4 ]
[ Count is 5 ]

4. Until Exit

#!/bin/bash
until [ "$user_input" == "exit" ]; do
    echo "Please enter your name (or type 'exit' to quit):"
    read user_input
    if [ -z "$user_input" ]; then
        echo "You did not provide any input. Please try again."
    elif [ "$user_input" != "exit" ]; then
        echo "Hello, $user_input!"
    fi
done

5. Countdown

#!/bin/bash
count=10
while [ $count -gt 0 ]; do
    echo "$count"
    count=$((count - 1))
done
echo "Liftoff!"

6. Sum 1 to 100

#!/bin/bash
sum=0
n=1
while [ $n -le 100 ]; do
    sum=$((sum + n))
    n=$((n + 1))
done
echo "Sum: $sum"
[ Sum: 5050 ]

7. Read a File

#!/bin/bash
while IFS= read -r line; do
    echo "Line: $line"
done < file.txt

8. Wait for File

#!/bin/bash
until [ -f /tmp/ready ]; do
    echo "Waiting..."
    sleep 1
done
echo "Ready!"

9. Wait for Service

#!/bin/bash
until curl -s http://localhost:8080/health > /dev/null; do
    echo "Service not ready..."
    sleep 2
done
echo "Service is up"

10. Retry with Limit

#!/bin/bash
attempts=0
until command_that_might_fail; do
    attempts=$((attempts + 1))
    if [ $attempts -ge 5 ]; then
        echo "Failed after 5 attempts"
        exit 1
    fi
    echo "Attempt $attempts failed, retrying..."
    sleep 2
done

11. Menu Loop

#!/bin/bash
while true; do
    echo "1) Show date"
    echo "2) Show disk"
    echo "3) Quit"
    read -p "Choice: " c
    case "$c" in
        1) date ;;
        2) df -h ;;
        3) break ;;
        *) echo "Invalid" ;;
    esac
done

12. Password Prompt

#!/bin/bash
attempts=0
while true; do
    read -s -p "Password: " pw
    echo
    if [ "$pw" = "secret" ]; then
        echo "Access granted"
        break
    fi
    attempts=$((attempts + 1))
    if [ $attempts -ge 3 ]; then
        echo "Too many attempts"
        exit 1
    fi
done

13. Multiplication Table

#!/bin/bash
i=1
while [ $i -le 5 ]; do
    j=1
    while [ $j -le 5 ]; do
        printf "%4d" $((i * j))
        j=$((j + 1))
    done
    echo
    i=$((i + 1))
done

14. Process Arguments

#!/bin/bash
while [ $# -gt 0 ]; do
    echo "Argument: $1"
    shift
done

15. Retry Until Success

#!/bin/bash
until ping -c1 server > /dev/null 2>&1; do
    echo "Server not reachable, retrying..."
    sleep 5
done
echo "Server is up"

16. Process CSV

#!/bin/bash
while IFS=, read -r name age city; do
    echo "Name: $name, Age: $age, City: $city"
done < people.csv

17. Countdown with Sleep

#!/bin/bash
for i in 3 2 1; do
    echo "$i..."
    sleep 1
done
echo "Go!"

18. Confirm Before Action

#!/bin/bash
until [ "$ans" = "y" ] || [ "$ans" = "n" ]; do
    read -p "Continue? (y/n): " ans
done
if [ "$ans" = "y" ]; then
    echo "Proceeding"
fi

19. Infinite Loop with Kill Switch

#!/bin/bash
while true; do
    echo "[$(date +%T)] Working..."
    if [ -f /tmp/stop ]; then
        echo "Stop file found, exiting"
        break
    fi
    sleep 5
done

20. Full Script Example

#!/bin/bash

count=1
while [ $count -le 5 ]; do
    echo "Count is $count"
    count=$((count + 1))
done

count=1
while [ $count -le 5 ]; do
    if [ $count -eq 3 ]; then
        echo "Breaking loop at count 3."
        break
    fi
    echo "Count is $count"
    count=$((count + 1))
done

count=1
while [ $count -le 5 ]; do
    if [ $count -eq 3 ]; then
        echo "Skipping count 3."
        count=$((count + 1))
        continue
    fi
    echo "Count is $count"
    count=$((count + 1))
done

until [ "$user_input" == "exit" ]; do
    echo "Please enter your name (or type 'exit' to quit):"
    read user_input
    if [ -z "$user_input" ]; then
        echo "You did not provide any input. Please try again."
    elif [ "$user_input" != "exit" ]; then
        echo "Hello, $user_input!"
    fi
done

Visual: while vs until

┌──────────────────────────────────────────────┐
│              while loop                      │
│                                              │
│  ┌────────────────────────────────────┐      │
│  │  condition?  ──── true ────►  body │      │
│  └────────┬───────────────────────────┘      │
│           │                                  │
│          false                               │
│           │                                  │
│           ▼                                  │
│          exit                                │
│                                              │
│  Runs AS LONG AS condition is true.          │
│                                              │
└──────────────────────────────────────────────┘

┌──────────────────────────────────────────────┐
│              until loop                      │
│                                              │
│  ┌────────────────────────────────────┐      │
│  │  condition?  ──── false ───►  body │      │
│  └────────┬───────────────────────────┘      │
│           │                                  │
│          true                                │
│           │                                  │
│           ▼                                  │
│          exit                                │
│                                              │
│  Runs UNTIL condition becomes true.          │
│                                              │
└──────────────────────────────────────────────┘

Visual: break and continue

┌──────────────────────────────────────────────┐
│           break                              │
│                                              │
│  iteration 1  ✓                              │
│  iteration 2  ✓                              │
│  iteration 3  → break → exit loop            │
│  iteration 4  (never runs)                   │
│  iteration 5  (never runs)                   │
│                                              │
└──────────────────────────────────────────────┘

┌──────────────────────────────────────────────┐
│           continue                           │
│                                              │
│  iteration 1  ✓                              │
│  iteration 2  ✓                              │
│  iteration 3  → continue → skip to next      │
│  iteration 4  ✓                              │
│  iteration 5  ✓                              │
│                                              │
└──────────────────────────────────────────────┘

Summary

ConceptSyntaxExample
whilewhile [ cond ]; do ... donewhile [ $i -le 5 ]; do ...; done
untiluntil [ cond ]; do ... doneuntil [ -f f ]; do sleep 1; done
Infinitewhile truewhile true; do ...; done
breakbreakExit the loop
continuecontinueSkip to next iteration
break Nbreak 2Exit N levels
continue Ncontinue 2Continue outer loop
Read filewhile read -r linewhile IFS= read -r line; do ...; done < f
Process argswhile [ $# -gt 0 ]while [ $# -gt 0 ]; do ...; shift; done
Retryuntil commanduntil curl URL; do sleep 1; done

Key takeaways:

  • while runs while the condition is true; until runs until the condition becomes true
  • Both check the condition before each iteration — the body may run zero times
  • Always change something inside the loop so the condition eventually becomes false
  • break exits the loop immediately; continue skips to the next iteration
  • In a while loop, increment before continue or you’ll loop forever on the same value
  • Use while true with a break for menus and retry loops
  • Use until for polling — waiting for a file, a service, or a condition
  • Use while IFS= read -r line to read files line by line
  • Use break 2 and continue 2 to control nested loops (bash 4+)
  • Add a safety limit to any infinite loop — a counter or a max attempts check
  • Redirect input with done < file instead of piping — avoids subshell variable loss

Remember: Loops are how you repeat work. while says “keep going while this is true.” until says “keep going until this becomes true.” Both need something to change inside — forget that and you’ve written an infinite loop. Use break to exit early and continue to skip ahead. For files, use while IFS= read -r. For waiting, use until. Master these two loops, and you can handle any repetitive task in shell scripting.


Stop using slow, ad-bloated tool sites! 🤮

🔎 Search “KandZ Tools” on Google to use many professional utilities for free.

KandZ.me is the ultimate minimalist hub for:
✅ Finance (Mortgage, Interest, Inflation)
✅ Tech (Base64, JSON, Dev Suite, IP)
✅ Health (BMI, BMR, TDEE)
✅ Productivity (Timer, Workspace, QR)

⚡️ Fast & Private
🔒 No data leaves your device
💎 100% Free

🔗 Use it now: https://tools.kandz.me
🔖 Bookmark it—you’ll need it later!