Shell脚本while循环语法详解

1.概述

本章中,开始介绍循环的概念。循环可用于重复执行程序的某一部分,本文介绍while循环。

2.while

while命令的语法如下:

while commands; do commands; done

示例:

[sysadmin@ansible bin]$ cat while-count
#!/bin/bash

# while-count

count=1

while [[ "$count" -le 5 ]]; do
        echo "$count"
        count=$((count + 1))
done
echo "Finshed."
[sysadmin@ansible bin]$ while-count
1
2
3
4
5
Finshed.

和if一样,while会判断命令列表的退出状态值。只要退出状态值为0,就执行循环内的命令。使用while命令改进read-menu程序。

[sysadmin@ansible bin]$ cat while-menu
#!/bin/bash

#while-menu

DELAY=3 #显示结果的秒数

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 "$REPLY"
        fi

        if [[ "$REPLY" == 3 ]]; then
                if [[ "$(id -u)" -eq 0 ]]; then
                        echo "Home Space Utilization (ALL Users)"
                        du -sh /home/*
                else
                        echo "Home Space Utilizaion ($USER)"
                        du -sh "$HOME"
                fi
                sleep "$DELAY"
        fi
else
        echo "Invalid entry." >&2
        sleep "$DELAY"
fi
done
echo "Program terminated."

3. 跳出循环

Bash提供了两个内建命令,可用户控制循环内部的程序流程。break命令会立即终止循环,程序从循环之后的语句开始继续执行。continue命令则跳过本次循环中剩余的部分,直接开始下一次循环。下面这个版本的while-menu程序引入了break和continue:

#!/bin/bash

#while-menu

DELAY=3 #显示结果的秒数

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-3]$ ]]; then
        if [[ "$REPLY" == 1 ]]; then
                echo "Hostname: $HOSTNAME"
                uptime
                sleep "$DELAY"
                continue
        fi

        if [[ "$REPLY" == 2 ]]; then
                df -h
                sleep "$REPLY"
                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 Utilizaion ($USER)"
                        du -sh "$HOME"
                fi
                sleep "$DELAY"
                continue
        fi

        if [[ "$REPLY" == 0 ]]; then
                break
        fi
else
        echo "Invalid entry." >&2
        sleep "$DELAY"
fi
done
echo "Program terminated."

true命令向while提供退出状态值,从而形成一个无限循环。true的退出状态值始终为0,所以循环永不会停止。因为循环不会自己结束,所以需要程序员提供某种方式,使其在恰当的时刻跳出循环。在上述脚本中,如果用户选择了0,break命令用于退出循环。为使脚本执行更加高效,在其他处理菜单选项的脚本部分的结尾使用了continue。在确认用户选择之后,continue使脚本可以跳过不必要的代码。

4. until

until与while大同小异,只不过while在退出状态值不为0时结束循环,而until则与之相反。until循环会在接收到为0的退出状态时终止。使用until改写while-count脚本。

[sysadmin@ansible bin]$ cat until-count
#!/bin/bash

# unitil-count

count=1

until [[ "$count" -gt 5 ]]; do
        echo "$count"
        count=$((count + 1))
done
echo "Finshed."
[sysadmin@ansible bin]$ until-count
1
2
3
4
5
Finshed.
[sysadmin@ansible bin]$

5. 使用循环读取文件

while和until都能处理标准输入,这使使用while和until循环处理文件成为可能。

[sysadmin@ansible bin]$ cat distros.txt
aa  bb  cc
[sysadmin@ansible bin]$ cat while-read
#!/bin/bash

# while-read

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

[sysadmin@ansible bin]$ while-read
Distro: aa      Version: bb     Released: cc

为了将文件重定向到循环,在done语句之后加上了重定向操作符。循环会使用read读入被重定向文件的各个字段。每读入一行,read将返回退出状态值0并退出,直至读完整个文件。这时,它返回的是非0退出状态,因此结束了循环。
也可以通过管道将标准输入传入循环

#!/bin/bash

# while-read

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

这里,我们获取sort命令的输出结果并显示文本流。但由于管道使循环在子Shell中执行,任何在循环内创建或复制的变量在循环结束后都荡然无存,这点很重要,一定要记住。

猜你喜欢

转载自blog.csdn.net/weixin_43770382/article/details/128085233