本章中,开始介绍循环的概念。循环可用于重复执行程序的某一部分,本文介绍while循环。
while命令的语法如下:
while commands; do commands; done
示例:
[sysadmin@ansible bin]$ cat while-count
#!/bin/bash# while-countcount=1while [[ "$count" -le 5 ]]; doecho "$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-menuDELAY=3 #显示结果的秒数while [[ "$REPLY" != 0 ]]; doclearcat <<- _EOF_Please Select:1.Display System Information2.Display Disk Space3.Display Home Space Utilization0.Quit_EOF_
read -p "Enter selection [0-3] > "if [[ "$REPLY" =~ ^[0-3]$ ]]; thenif [[ "$REPLY" == 1 ]]; thenecho "Hostname: $HOSTNAME"uptimesleep "$DELAY"fiif [[ "$REPLY" == 2 ]]; thendf -hsleep "$REPLY"fiif [[ "$REPLY" == 3 ]]; thenif [[ "$(id -u)" -eq 0 ]]; thenecho "Home Space Utilization (ALL Users)"du -sh /home/*elseecho "Home Space Utilizaion ($USER)"du -sh "$HOME"fisleep "$DELAY"fi
elseecho "Invalid entry." >&2sleep "$DELAY"
fi
done
echo "Program terminated."
Bash提供了两个内建命令,可用户控制循环内部的程序流程。break命令会立即终止循环,程序从循环之后的语句开始继续执行。continue命令则跳过本次循环中剩余的部分,直接开始下一次循环。下面这个版本的while-menu程序引入了break和continue:
#!/bin/bash#while-menuDELAY=3 #显示结果的秒数while true; doclearcat <<- _EOF_Please Select:1.Display System Information2.Display Disk Space3.Display Home Space Utilization0.Quit_EOF_
read -p "Enter selection [0-3] > "if [[ "$REPLY" =~ ^[0-3]$ ]]; thenif [[ "$REPLY" == 1 ]]; thenecho "Hostname: $HOSTNAME"uptimesleep "$DELAY"continuefiif [[ "$REPLY" == 2 ]]; thendf -hsleep "$REPLY"continuefiif [[ "$REPLY" == 3 ]]; thenif [[ "$(id -u)" -eq 0 ]]; thenecho "Home Space Utilization (ALL Users)"du -sh /home/*elseecho "Home Space Utilizaion ($USER)"du -sh "$HOME"fisleep "$DELAY"continuefiif [[ "$REPLY" == 0 ]]; thenbreakfi
elseecho "Invalid entry." >&2sleep "$DELAY"
fi
done
echo "Program terminated."
true命令向while提供退出状态值,从而形成一个无限循环。true的退出状态值始终为0,所以循环永不会停止。因为循环不会自己结束,所以需要程序员提供某种方式,使其在恰当的时刻跳出循环。在上述脚本中,如果用户选择了0,break命令用于退出循环。为使脚本执行更加高效,在其他处理菜单选项的脚本部分的结尾使用了continue。在确认用户选择之后,continue使脚本可以跳过不必要的代码。
until与while大同小异,只不过while在退出状态值不为0时结束循环,而until则与之相反。until循环会在接收到为0的退出状态时终止。使用until改写while-count脚本。
[sysadmin@ansible bin]$ cat until-count
#!/bin/bash# unitil-countcount=1until [[ "$count" -gt 5 ]]; doecho "$count"count=$((count + 1))
done
echo "Finshed."
[sysadmin@ansible bin]$ until-count
1
2
3
4
5
Finshed.
[sysadmin@ansible bin]$
while和until都能处理标准输入,这使使用while和until循环处理文件成为可能。
[sysadmin@ansible bin]$ cat distros.txt
aa bb cc
[sysadmin@ansible bin]$ cat while-read
#!/bin/bash# while-readwhile read distro version release; doprintf "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-readsort -k 1,1 -k 2n distros.txt | while read distro version release; doprintf "Distro: %s\tVersion: %s\tReleased: %s\n" \"$distro" \"$version" \"$release"
done
这里,我们获取sort命令的输出结果并显示文本流。但由于管道使循环在子Shell中执行,任何在循环内创建或复制的变量在循环结束后都荡然无存,这点很重要,一定要记住。