shell可以重复地执行特定的指令,直到特定的条件被满足为止。这重复执行的一组命令就叫做循环。
每一个循环都具有以下特点:
- 首先,循环条件中使用的变量必须是已初始化的,然后在循环中开始执行。
- 在每一次循环开始时进行一次测试。
- 重复的执行一个代码块
7.1 for循环
7.1.1 for循环语法
for循环的基本语法:
for VAR in item1 item2 ... item do command1 command2 ... ... commandN done
for循环变量的内容的语法:
for VAR in $fileNames do command1 command2 ... ... commandN done
for循环命令替换的语法:
for VAR in $(Linux-command-name) #或者使用: for VAR in `Linux-command-name` do command1 command2 ... ... commandN done
for循环还有三项表达式语法,这种语法与C语言中常见for循环使用方法相同。
for循环三项表达式语法:
for (( EXP1; EXP2; EXP3 )) do command1 command2 ... ... commandN done
上述语法以三项参数循环控制表达式为特征,它由一个初始化式(EXP1)、循环测试或条件(EXP2)和一个计算表达式(EXP3)组成。
在for循环中,每次指定列表中的(iterm1…itermN)新值被赋给变量VAR后,for循环都会执行一次,它将重复运行‘do’和‘done’之间的所有语句,直到条件不满足时为止。这些列表或数值通常是:
- 字符串
- 数字
- 命令行
- 参数
- 文件名
- Linux命令的输出
我们来看一个简单的for循环的脚本:
#!/bin/bash for i in 1 2 3 # 从1~3循环 do echo "The for loop is run $i times" done
接下来看一个字符串的循环示例:
#! /bin/bash for linux in Debin Redhat Suse Fedora do echo "The OS is : $linux" done
使用变量内容的for循环示例:
#! /bin/bash filenames="/etc/yp.conf /etc/nsswitch.sh /etc/auto.master /etc/resolv.conf" # 文件名以空格分隔 for file in $filenames do [ -f $file ] && echo "The file $file was found" || echo "*** Error : The file $file was missing. ***" done
使用命令替换的for循环实例:
#! /bin/bash echo "Printing file list in /tmp/directory:" for file in 'ls /tmp/*' do echo $file done
7.1.2 嵌套for循环语句
嵌套循环的意思即是在循环中循环。下面我们看一个简单的嵌套for循环的实例:
#! /bin/bash for (( i = 0; i < 3; i++ )) do for(( j = 0; j < 5; j++ )) do echo -n "* " done echo "" done
那么脚本运行后的结果类似如下所示:
$ chomd =x simplenestedfor.sh $ ./simplenestedfor.sh * * * * * * * * * * * * * * *
7.2 while循环
while循环语法用于重复执行一个命令列表。
7.2.1 while循环语法
while循环语句的语法:
while [ CONDITION ] do command1 command2 … ... commandN done
当条件CONDITION为真时,command1 … commandN将被执行。例如逐行地读取一个文本文件的内容,其语法类似如下:
while IFS= read -r line do command1 on $line command2 on $line ... ..... commandN done < "/path/to/file"
我们看一个简单的使用while循环的实例
#! /bin/bash var=1 while [ $var -le 3 ] do echo "The for loop is run $var times." var=$(( var + 1 )) done
运行结果如下:
$ chomd +x whileloop.sh $ ./whileloop.sh The for loop is run 1 times The for loop is run 2 times The for loop is run 3 times
我们可以将read命令和while循环结合使用来读取一个文本文件:
#!/bin/bash file=$1 if [ $# -lt 1 ]; then echo "Uasge: $0 FILEPATH" exit fi while read -r line do echo $line done < "$file"
执行该文件:
bash whichereadfile.sh file
还可以按列读取文件的内容,如下脚本在上述脚本的基础上将文件分为3列输出:
#!/bin/bash file=$1 if [ $# -lt 1 ]; then echo "Uasge: $0 FILEPATH" exit fi while read -r f1 f2 f3 do echo "Field 1: $f1 ===> Field 2: $f2 ===> Field 3: $f3" done < "$file"
7.2.2定义无限while循环
你可以将while循环和专用命令“:”结合使用来定义一个无限循环。在几种情况下,这是一个期望的行为。例如,菜单驱动程序通常持续运行到用户选择退出主菜单(循环)。由于循环固有的一些特性,当条件永远不被满足时,也会发生一个无限循环。定义一个无限while循环可以使用如下三种命令:
- true命令 - 不做任何事,表示成功,总是返回退出状态码0。
- false命令 - 不做任何事,表示成功,总是返回退出状态码1。
- :命令 – 无作用,此命令也不做任何事,总是返回退出状态码。
使用":"命令定义一个无限循环:
#! /bin/bash while : do echo "Do something..." echo "Hit [ CTRL+C ] to stop!" sleep 3 done
注意: ":"命令是Bash的内部命令。
使用true命令定义一个无限循环:
#! /bin/bash while true do echo "Do something..." echo "Hite [ CTRL+C ] to stop!" sleep 3 done
使用false命令定义一个无限循环的语法和使用true命令或“:”命令的语法相似,只需将上述脚本中的true替换为false即可,它们的运行结果相同。
下面是一个菜单驱动程序,它将持续地运行,直到用户按下“4”选择退出为止,下面是实例
#! /bin/bash while : do clear #清理终端屏幕 echo "1. Display date and time." echo "2. Display system information." echo "3. Display what users are doing." echo "4. Exit" read -p "Enter your choice [1-4 ]: " choice #从标准输入中读取用户的输入,并赋值给变量choice case $choice in 1) echo "Today is $(date +%Y-%m-%d.)" #打印当前日期,格式为“YYYY-MM-DD” echo "Current time: $(date +%H:%M:%S)" #打印当前时间,格式为“hh:mm:ss” read -p "Press [Enter] key to continue..." readEnterKey #只读入回车换行符 ;; 2) uname -a #打印系统信息 read -p "Press [Enter] key to continue..." readEnterKey ;; 3) w #显示系统中当前登录的用户,及用户当前运行的命令 read -p "Press [Enter] key to continue..." readEnterKey ;; 4) echo "Bye!" exit 0 ;; *) echo "Error: Invalid option!" read -p "Press [Enter] key to continue..." readEnterKey ;; esac done
结果如下:
=========== MAIN - MENU =========== 1.Display date and time. 2.Display system information. 3.Display what users are doing. 4.Exit Enter your choice [ 1-4 ]: 1 Today is 2013-10-31. Current time:16:43:42 Press [Enter] key to continue...
7.3until循环语法
until循环与while循环类似,也同样基于一个条件。但until循环的判断条件正好与while循环的判断条件相反,until循环在条件为假的情况下才会持续地运行。一旦条件被满足,即为真,就会退出循环。until循环的语法如下所示:
until [ CONDITION ] do command1 command2 … … command done
until循环与while循环相比:
- until循环执行直到返回0状态。
- while循环执行直到返回非0 状态。
- until循环总是执行至少一次。
下面看一个until循环的实例:
#!/bin/bash var=1 until [ $var -gt 3 ] do echo "the for loop is run $var times." var=$(( var + 1 )) done
脚本结果如下:
$chmod +x untilloop.sh $./untilloop.sh The for loop is run 1 times. The for loop is run 2 times. The for loop is run 3 times.
7.4 select循环语法
Bash还提供select循环。其语法如下所示:
select VAR in LIST do command1 command2 ... ... commandN done
select循环语句具有如下特点:
- select语句使用Bash内部变量PS3的值作为它的提示符信息。
- 打印到屏幕上的列表LIST中的每一项会在前面加上一个数字编号。
- 当用户输入的数字与某一个数字编号一致时,列表中相应的项即被赋予给变量VAR。
- 如果用户输入的为空,将重新显示列表LIST中的项和提示符信息。
- 可以通过添加一个退出选项,或输入CTRL+C或CTRL+D退出select循环。
下面我们看一个实例:
#! /bin/bash PS3="Run command:" #定义 PS3 提示符 select choice in date w hostname "uname -a" Exit #指定select循环的列表 do case $choice in date) echo "==================================" echo "Current system date and time: " echo "==================================" $choice #直接将变量的值作为命令运行 ;; w) echo "==================================" echo "Who is logged on and what they are doing:" echo "==================================" $choice ;; hostname) echo "==================================" echo "Hostname:" echo "==================================" $choice ;; "uname -a") echo "==================================" echo "System information:" echo "==================================" $choice ;; Exit) echo "Bye!" exit 0 ;; esac done
结果如下:
chmod -x selectloop.sh ./selectloop.sh date w hostname uname -a Exit Run command:1 ==================== Current system date and time: ==================== Fri Nov 1 18:40:36 CST 2013 Run command: date w hostname uname -a Exit Run command:4 ============== System information: ============== Linux localhost 2.6.18-238.9.1.e15PAE #1 SMP Tue Apr 12 19:28:32 EDT 2011 Run command:5 Bye!
7.5 循环控制
break和continue是Bash中的循环控制命令,其用法与其他编程语言中的同名语句完全一致。
7.5.1break语句
break语句用于从for、while、until或select循环中退出,停止循环的执行。
break语句的语法如下所示:
break [n]
n代表嵌套循环的层级,如果指定了n,break将退出n级嵌套循环。如果没有指定n或n不大于等于1,则退出状态码为0,否则退出状态码为n。
下面看一个实例:
#! /bin/bash # 如果未指定参数,则打印脚本的使用方法,并返回退出状态码1 [ $# -eq 0 ] && { echo "Usage: $0 filepath"; exit 1; } #将位置参数1的值赋给变量match match=$1 found=0 #遍历目录/etc下的所以文件 for file in /etc/* do #如果文件的路径与指定的参数文件路径相匹配,则打印文件已找到,并退出for循环 if [ $file == "$match" ] then echo "The file $match was found!" found=1 #使用break命令退出for循环 break fi done [ $found -ne 1 ] && echo "The file $match not found in /etc directory."
此脚本的运行结果将类似如下所示:
$ chmod +x forbreak.sh $ ./forbreak.sh /etc/inittab The file /etc/inittab was found! $ ./forbraek.sh /etc/host The file /etc/host not found in /etc directory.
使用break n 语句退出嵌套循环:
#! /bin/bash # 如果未指定参数,则打印脚本的使用方法,并返回退出状态码 1 [ $# -eq 0 ] && { echo "Usage: $0 command"; exit 1; } #将位置参数1的值赋给变量match match=$1 found=0 for dir in /bin /usr/bin do # 遍历目录下的所有文件 for file in $dir/* do # 如果文件名与指定的参数文件名相匹配,则打印命令已找到,并退出嵌套的for循环 if [ $(basename $file) == "$match" ] then echo "The command $match was found!" found=1 # 退出两层的for循环 break 2 fi done done [ $found -ne 1 ] && echo "The command $match not found."
7.5.2continue语句
continue语句用于跳过循环体中剩余的命令直接跳转到循环体的顶部,而重新开始循环的下一次重复。continue语句可以应用于for、while或until循环。continue语句的语法如下所示:
continue [n]
接下来看一个在循环中使用continue语句的实例:
#! /bin/bash #如果运行脚本时未指定参数,则打印脚本的使用方法,并返回退出状态码1 [ $# -eq 0 ] && { echo "Usage: $O directory"; exit 1; } #如果指定的目录不存在,则打印错误信息,并返回退出状态码1 [ ! -d $1 ] && { echo "Error: The directory $l does not exist."; exit 1;} #如果没有成功切换到指定的目录,则打印相应的错误信息,并返回退出状态码1 cd $1 || { echo "Connot cd to the directory $1"; exit 1; } #遍历指定目录下的所有文件 for filename in $(ls) do #如果文件名不包含大写字母,则直接跳转到下一次循环 if [ $filename != *[[:upper:]]* ] then #忽略for循环体中剩余的语句直接跳转到下一次循环 continue fi #将变量filename中的字母转换为小写 new=`echo $filename | tr 'A-Z' 'a-z'` #将文重命名 mv $filename $new echo "The file $filename renamed to $new." done
7.6小结
下面我们总结一下本章所学的主要知识:
- Shell可以重复地执行特定的指令,直到特定的条件被满足时为止。这重复执行的一组命令就叫做循环。
- 循环具有以下特点:
-
- 循环条件中使用的变量必须是已初始化的,然后在循环中开始执行;
-
- 在每一次循环开始时进行一次测试;
-
- 重复地执行一个代码块。
- 在for循环中,每次指定列表中的(iterm1…itermN)新值被赋给变量VAR后,for循环都会执行一次,它将重复运行‘do’和‘done’之间的所有语句,直到条件不满足时为止。
- for循环也有三项表达式语法,其语法与C语言中常见的for循环使用方法相同。
- while循环语句用于重复地执行一个命令列表。
- while循环可以与read命令结合使用来读取一个文本文件。
- while循环和专用命令“:”结合使用来定义一个无限循环。
- 定义一个无限while循环可以使用以下三种命令: true命令、false命令和:命令
- until循环与while循环类似,也同样基于一个条件。但until循环的判断条件正好与while循环的判断条件相反,until循环在条件为假的情况下才会持续地运行。一旦条件被满足,即为真,就会退出循环。
- select循环语句具有如下特点:
-
- select语句使用Bash内部变量PS3的值作为它的提示符信息。
-
- 打印到屏幕上的列表LIST中的每一项会在前面加上一个数字编号。
-
- 当用户输入的数字与某一个数字编号一致时,列表中相应的项即被赋予给变量VAR。
-
- 如果用户输入的为空,将重新显示列表LIST中的项和提示符信息。
-
- 可以通过添加一个退出选项,或输入CTRL+C或CTRL+D退出select循环。
- break和continue是Bash中的循环控制命令,其用法与在其它编程语言中的同名语句完全一致。
- break语句用于从for、while、until或select循环中退出,停止循环的执行。使用break n将退出n级嵌套循环。
- continue语句用于跳过循环体中剩余的命令直接跳转到循环体的顶部,而重新开始循环的下一次重复。continue语句可以应用于for、while或until循环。