Passa al contenuto principale

1. Looping with while and until

The syntax of the while command is as follows:

while commands; do commands; done
  1. A simple example:

    while-count.sh
    #!/bin/bash

    # while-count: display a series of numbers

    count=1

    while [[ "$count" -le 5 ]]; do
    echo "$count"
    count=$((count + 1))
    done
    echo "Finished."
    vim while-count.sh
    ./while-count.sh
  2. We can use a while loop to improve the menu program from the previous lesson:

    while-menu.sh
    #!/bin/bash

    # while-menu: a menu driven system information program

    DELAY=3 # Number of seconds to display results

    while [[ "$REPLY" != 0 ]]; do
    clear
    cat <<- _EOF_
    Please Select:
    1. Display System Information
    2. Display Disk Space
    3. Display Home Space Utilization
    0. Quit
    _EOF_
    read -p "Enter selection [0-3] > "

    if [[ "$REPLY" =~ ^[0-3]$ ]]; then
    if [[ $REPLY == 1 ]]; then
    echo "Hostname: $HOSTNAME"
    uptime
    sleep "$DELAY"
    fi
    if [[ "$REPLY" == 2 ]]; then
    df -h .
    sleep "$DELAY"
    fi
    if [[ "$REPLY" == 3 ]]; then
    if [[ "$(id -u)" -eq 0 ]]; then
    echo "Home Space Utilization (All Users)"
    du -sh /home/*
    else
    echo "Home Space Utilization ($USER)"
    du -sh "$HOME"
    fi
    sleep "$DELAY"
    fi
    else
    echo "Invalid entry."
    sleep "$DELAY"
    fi
    done
    echo "Program terminated."
    vim while-menu.sh

    By enclosing the menu in a while loop, we are able to have the program repeat the menu display after each selection. The loop continues as long as REPLY is not equal to 0 and the menu is displayed again, giving the user the opportunity to make another selection. At the end of each action, a sleep command is executed so the program will pause for a few seconds to allow the results of the selection to be seen before the screen is cleared and the menu is redisplayed. Once REPLY is equal to 0, indicating the “quit” selection, the loop terminates and execution continues with the line following done.

    ./while-menu.sh
  3. Inside a loop in bash we can use break and continue.

    while-menu2.sh
    #!/bin/bash

    # while-menu: a menu driven system information program

    DELAY=3 # Number of seconds to display results

    while true; do
    clear
    cat <<- _EOF_
    Please Select:
    1. Display System Information
    2. Display Disk Space
    3. Display Home Space Utilization
    0. Quit
    _EOF_
    read -p "Enter selection [0-3] > "

    if [[ "$REPLY" == 0 ]]; then
    break
    fi
    if [[ ! "$REPLY" =~ ^[0-3]$ ]]; then
    echo "Invalid entry."
    sleep "$DELAY"
    continue
    fi
    if [[ $REPLY == 1 ]]; then
    echo "Hostname: $HOSTNAME"
    uptime
    sleep "$DELAY"
    continue
    fi
    if [[ "$REPLY" == 2 ]]; then
    df -h .
    sleep "$DELAY"
    continue
    fi
    if [[ "$REPLY" == 3 ]]; then
    if [[ "$(id -u)" -eq 0 ]]; then
    echo "Home Space Utilization (All Users)"
    du -sh /home/*
    else
    echo "Home Space Utilization ($USER)"
    du -sh "$HOME"
    fi
    sleep "$DELAY"
    continue
    fi
    done
    echo "Program terminated."
    vim while-menu2.sh
    ./while-menu2.sh
  4. The until loop is very similar to the while loop, but with a negated condition.

    until-count.sh
    #!/bin/bash

    # until-count: display a series of numbers

    count=1

    until [[ "$count" -gt 5 ]]; do
    echo "$count"
    count=$((count + 1))
    done
    echo "Finished."
    vim until-count.sh
    ./until-count.sh
  5. We can also read the standard input with while and until:

    cat distros.txt
    while-read.sh
    #!/bin/bash

    # while-read: read lines from a file

    while read distro version release
    do
    printf "Distro: %s\tVersion: %s\tReleased: %s\n" \
    "$distro" \
    "$version" \
    "$release"
    done < distros.txt
    vim while-read.sh

    The while loop will continue as long as the read command is successful getting input from stdin, and we redirect stdin to get data from the file distros.txt (by using the operator < at the end of the while command).

    ./while-read.sh

    We can also use a pipe (|) to redirect the stdin:

    while-read2.sh
    #!/bin/bash

    # while-read2: read lines from a file

    sort -k 1,1 -k 2n distros.txt | \
    while read distro version release; do
    printf "Distro: %s\tVersion: %s\tReleased: %s\n" \
    "$distro" \
    "$version" \
    "$release"
    done
    vim while-read2.sh

    Notice that we are breaking long commands by adding a \ at the end of a line, in order to make the program more readable and clear.

    ./while-read2.sh
Loading asciinema cast...