对代码块的操作是构造组织shell脚本的关键. 循环和分支结构为脚本编程提供了操作代码块的工具.
循环就是重复一些命令的代码块,如果条件不满足就退出循环.
for loops
for arg in [list] 这是一个基本的循环结构.它与C的for结构有很大不同.
for arg in [list] do command(s)... done
在循环的每次执行中,arg将顺序的存取list中列出的变量..
1 for arg in "$var1" "$var2" "$var3" ... "$varN" 2 # 在第1次循环中, arg = $var1 3 # 在第2次循环中, arg = $var2 4 # 在第3次循环中, arg = $var3 5 # ... 6 # 在第N次循环中, arg = $varN 7 8 # 在[list]中的参数加上双引号是为了防止单词被不合理地分割.
list中的参数允许包含通配符.
如果do和for想在同一行出现,那么在它们之间需要添加一个";".
for arg in [list] ; do
--------------------------------------------------------------------------------
例子 10-1. 循环的一个简单例子
1 #!/bin/bash 2 # 列出所有的行星名称. 3 4 for planet in Mercury Venus Earth Mars Jupiter Saturn Uranus Neptune Pluto 5 do 6 echo $planet # 每个行星被单独打印在一行上. 7 done 8 9 echo 10 11 for planet in "Mercury Venus Earth Mars Jupiter Saturn Uranus Neptune Pluto" 12 # 所有的行星名称打印在同一行上. 13 # 整个'list'只有一个变量,用""封成一个变量. 14 do 15 echo $planet 16 done 17 18 exit 0
--------------------------------------------------------------------------------
每个[list]中的元素都可能包含多个参数.在处理参数组时,这是非常有用的.在这种情况下,使用set命令(见例子 11-15)来强制解析每个[list]中的元素,并且分配每个解析出来的部分到一个位置参数中.
--------------------------------------------------------------------------------
例子 10-2. 每个[list]元素带两个参数的for循环
1 #!/bin/bash 2 # 再访行星. 3 4 # 分配行星的名字和它距太阳的距离. 5 6 for planet in "Mercury 36" "Venus 67" "Earth 93" "Mars 142" "Jupiter 483" 7 do 8 set -- $planet # Parses variable "planet" and sets positional parameters. 9 # "--" 将防止$planet为空,或者是以一个破折号开头. 10 11 # 可能需要保存原始的位置参数,因为它们被覆盖了. 12 # 一种方法就是使用数组, 13 # original_params=("$@") 14 15 echo "$1 $2,000,000 miles from the sun" 16 #-------two tabs---把后边的0和$2连接起来 17 done 18 19 # (Thanks, S.C., for additional clarification.) 20 21 exit 0
--------------------------------------------------------------------------------
可以在for循环中的[list]位置放入一个变量.
--------------------------------------------------------------------------------
例子 10-3. 文件信息: 对包含在变量中的文件列表进行操作
1 #!/bin/bash 2 # fileinfo.sh 3 4 FILES="/usr/sbin/accept 5 /usr/sbin/pwck 6 /usr/sbin/chroot 7 /usr/bin/fakefile 8 /sbin/badblocks 9 /sbin/ypbind" # 你关心的文件列表. 10 # 扔进去一个假文件, /usr/bin/fakefile. 11 12 echo 13 14 for file in $FILES 15 do 16 17 if [ ! -e "$file" ] # 检查文件是否存在. 18 then 19 echo "$file does not exist."; echo 20 continue # 继续下一个. 21 fi 22 23 ls -l $file | awk '{ print $9 " file size: " $5 }' # 打印2个域. 24 whatis `basename $file` # 文件信息. 25 # 注意whatis数据库需要提前建立好. 26 # 要想达到这个目的, 以root身份运行/usr/bin/makewhatis. 27 echo 28 done 29 30 exit 0
--------------------------------------------------------------------------------
如果在for循环的[list]中有通配符(*和?),那将会产生文件名扩展,也就是文件名扩展(globbing).
--------------------------------------------------------------------------------
例子 10-4. 在for循环中操作文件
1 #!/bin/bash 2 # list-glob.sh: 在for循环中使用文件名扩展产生 [list] 3 4 echo 5 6 for file in * 7 # ^ 在表达式中识别文件扩展符时, 8 #+ Bash 将执行文件名扩展. 9 do 10 ls -l "$file" # Lists all files in $PWD (current directory). 11 # 回想一下,通配符"*"能够匹配所有文件, 12 #+ 然而,在"文件扩展符"中,是不能匹配"."文件的. 13 14 # 如果没匹配到任何文件,那它将扩展成自己 15 # 为了不让这种情况发生,那就设置nullglob选项 16 #+ (shopt -s nullglob). 17 # Thanks, S.C. 18 done 19 20 echo; echo 21 22 for file in [jx]* 23 do 24 rm -f $file # 只删除当前目录下以"j"或"x"开头的文件. 25 echo "Removed file \"$file\"". 26 done 27 28 echo 29 30 exit 0
--------------------------------------------------------------------------------
在一个for循环中忽略in [list]部分的话,将会使循环操作$@(从命令行传递给脚本的参数列表).一个非常好的例子,见例子 A-16.
--------------------------------------------------------------------------------
例子 10-5. 在for循环中省略in [list]
1 #!/bin/bash 2 3 # 使用两种方法来调用这个脚本,一种是带参数的情况,另一种不带参数. 4 #+ 观察此脚本的行为各是什么样的? 5 6 for a 7 do 8 echo -n "$a " 9 done 10 11 # 没有[list],所以循环将操作'$@' 12 #+ (包括空白的命令参数列表). 13 14 echo 15 16 exit 0
--------------------------------------------------------------------------------
也可以使用命令替换(command substitution)来产生for循环的[list].具体见例子 12-49, 例子 10-10 和例子 12-43.
--------------------------------------------------------------------------------
例子10-6. 使用命令替换来产生for循环的[list]
1 #!/bin/bash 2 # for-loopcmd.sh: 带[list]的for循环 3 #+ [list]是由命令替换产生的. 4 5 NUMBERS="9 7 3 8 37.53" 6 7 for number in `echo $NUMBERS` # for number in 9 7 3 8 37.53 8 do 9 echo -n "$number " 10 done 11 12 echo 13 exit 0 |