全国质量建设局特种作业网站,wordpress 微博秀,建设网站之前都需要准备什么,公司简介宣传册图片循环和分支对代码块的操作是构造组织shell脚本的关键. 循环和分支结构为脚本编程提供了操作代码块的工具.10.1. Loops循环就是重复一些命令的代码块,如果条件不满足就退出循环.for loopsfor arg in [list]这是一个基本的循环结构.它与C的for结构有很大不同.forarg in [list]do … 循环和分支对代码块的操作是构造组织shell脚本的关键. 循环和分支结构为脚本编程提供了操作代码块的工具.10.1. Loops循环就是重复一些命令的代码块,如果条件不满足就退出循环.for loopsfor arg in [list]这是一个基本的循环结构.它与C的for结构有很大不同.forarg 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想在同一行出现,那么在它们之间需要添加一个;.forarg 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 NUMBERS9 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下边是一个用命令替换来产生[list]的更复杂的例子.例子 10-7. 对于二进制文件的grep替换 1 #!/bin/bash 2 # bin-grep.sh: 在一个二进制文件中定位匹配字串. 3 4 # 对于二进制文件的一个grep替换 5 # 与grep -a的效果相似 6 7 E_BADARGS65 8 E_NOFILE66 9 10 if [ $# -ne 2 ] 11 then 12 echo Usage: basename $0 search_string filename 13 exit $E_BADARGS 14 fi 15 16 if [ ! -f $2 ] 17 then 18 echo File \$2\ does not exist. 19 exit $E_NOFILE 20 fi 21 22 23 IFS\n # 由Paulo Marcel Coelho Aragao提出的建议. 24 for word in $( strings $2 | grep $1 ) 25 # strings 命令列出二进制文件中的所有字符串. 26 # 输出到管道交给grep,然后由grep命令来过滤字符串. 27 do 28 echo $word 29 done 30 31 # S.C. 指出, 行23 - 29 可以被下边的这行来代替, 32 # strings $2 | grep $1 | tr -s $IFS [\n*] 33 34 35 # 试试用./bin-grep.sh mem /bin/ls来运行这个脚本. 36 37 exit 0大部分相同.例子 10-8. 列出系统上的所有用户 1 #!/bin/bash 2 # userlist.sh 3 4 PASSWORD_FILE/etc/passwd 5 n1 # User number 6 7 for name in $(awk BEGIN{FS:}{print $1} $PASSWORD_FILE ) 8 # 域分隔 : ^^^^^^ 9 # 打印出第一个域 ^^^^^^^^ 10 # 从password文件中取得输入 ^^^^^^^^^^^^^^^^^ 11 do 12 echo USER #$n $name 13 let n 1 14 done 15 16 17 # USER #1 root 18 # USER #2 bin 19 # USER #3 daemon 20 # ... 21 # USER #30 bozo 22 23 exit 0 24 25 # 练习: 26 # -------- 27 # 一个普通用户(或者是一个普通用户运行的脚本) 28 # 怎么能读取/etc/password呢? 29 # 这是否是一个安全漏洞? 为什么是?为什么不是?关于用命令替换来产生[list]的最后的例子.例子 10-9. 在目录的所有文件中查找源字串 1 #!/bin/bash 2 # findstring.sh: 3 # 在一个指定目录的所有文件中查找一个特定的字符串. 4 5 directory/usr/bin/ 6 fstringFree Software Foundation # 查看那个文件中包含FSF. 7 8 for file in $( find $directory -type f -name * | sort ) 9 do 10 strings -f $file | grep $fstring | sed -e s%$directory%% 11 # 在sed表达式中, 12 # 我们必须替换掉正常的替换分隔符/, 13 # 因为/碰巧是我们需要过滤的字串之一. 14 # 如果不用%代替/作为分隔符,那么这个操作将失败,并给出一个错误消息.(试试) 15 done 16 17 exit 0 18 19 # 练习 (容易): 20 # --------------- 21 # 将内部用的$directory和$fstring变量,用从 22 # 命令行参数代替.for循环的输出也可以通过管道传递到一个或多个命令中.例子 10-10. 列出目录中所有的符号连接(symboliclinks) 1 #!/bin/bash 2 # symlinks.sh: 列出目录中所有的符号连接文件. 3 4 5 directory${1-pwd} 6 # 如果没有其他的特殊指定, 7 # 默认为当前工作目录. 8 # 下边的代码块,和上边这句等价. 9 # ---------------------------------------------------------- 10 # ARGS1 # 需要一个命令行参数. 11 # 12 # if [ $# -ne $ARGS ] # 如果不是一个参数的话... 13 # then 14 # directorypwd # 当前工作目录 15 # else 16 # directory$1 17 # fi 18 # ---------------------------------------------------------- 19 20 echo symbolic links in directory \$directory\ 21 22 for file in $( find $directory -type l ) # -type l 就是符号连接文件 23 do 24 echo $file 25 done | sort # 否则列出的文件将是未排序的 26 # 严格上说,此处并不一定非要一个循环不可, 27 # 因为find命令的结果将被扩展成一个单词. 28 # 然而,这种方式很容易理解和说明. 29 30 # Dominik Aeneas Schnitzer 指出, 31 # 如果没将 $( find $directory -type l )用引用起来的话 32 # 那么将会把一个带有空白部分的文件名拆成以空白分隔的两部分(文件名中允许有空白). 33 # 即使这只将取出每个参数的第一个域. 34 35 exit 0 36 37 38 # Jean Helou 建议使用下边的方法: 39 40 echo symbolic links in directory \$directory\ 41 # 当前IFS的备份.要小心使用这个值. 42 OLDIFS$IFS 43 IFS: 44 45 for file in $(find $directory -type l -printf %p$IFS) 46 do # ^^^^^^^^^^^^^^^^ 47 echo $file 48 done|sort循环的输出可以重定向到文件中,我们对上边的例子做了一点修改.例子 10-11. 将目录中的符号连接文件名保存到一个文件中 1 #!/bin/bash 2 # symlinks.sh: 列出目录中所有的符号连接文件. 3 4 OUTFILEsymlinks.list # 保存的文件 5 6 directory${1-pwd} 7 # 如果没有其他的特殊指定, 8 # 默认为当前工作目录. 9 10 11 echo symbolic links in directory \$directory\ $OUTFILE 12 echo --------------------------- $OUTFILE 13 14 for file in $( find $directory -type l ) # -type l 为寻找类型为符号链接的文件 15 do 16 echo $file 17 done | sort $OUTFILE # 循环的输出 18 # ^^^^^^^^^^^^^ 重定向到一个文件中. 19 20 exit 0有一种非常像C语言的for循环的语法形式.这需要使用(()).例子 10-12. 一个C风格的for循环 1 #!/bin/bash 2 # 两种循环到10的方法. 3 4 echo 5 6 # 标准语法. 7 for a in 1 2 3 4 5 6 7 8 9 10 8 do 9 echo -n $a 10 done 11 12 echo; echo 13 14 # 15 16 # 现在, 让我们用C风格的语法做同样的事. 17 18 LIMIT10 19 20 for ((a1; a LIMIT ; a)) # 双圆括号, 并且LIMIT变量前边没有 $. 21 do 22 echo -n $a 23 done # 这是一个借用ksh93的结构. 24 25 echo; echo 26 27 # 28 29 # 让我们使用C的逗号操作符,来同时增加两个变量的值. 30 31 for ((a1, b1; a LIMIT ; a, b)) # 逗号将同时进行2条操作. 32 do 33 echo -n $a-$b 34 done 35 36 echo; echo 37 38 exit 0参考例子26-15, 例子26-16, 和 例子A-6.---现在来一个现实生活中使用的for循环.例子 10-13. 在batch mode中使用efax 1 #!/bin/bash 2 # Faxing (fax 必须已经被安装过了). 3 4 EXPECTED_ARGS2 5 E_BADARGS65 6 7 if [ $# -ne $EXPECTED_ARGS ] 8 # 检查命令行参数的个数是否正确. 9 then 10 echo Usage: basename $0 phone# text-file 11 exit $E_BADARGS 12 fi 13 14 15 if [ ! -f $2 ] 16 then 17 echo File $2 is not a text file 18 exit $E_BADARGS 19 fi 20 21 22 fax make $2 # 从文本文件中创建传真格式的文件. 23 24 for file in $(ls $2.0*) # 连接转换过的文件. 25 # 在变量列表中使用通配符. 26 do 27 fil$fil $file 28 done 29 30 efax -d /dev/ttyS3 -o1 -t T$1 $fil # 干活的地方. 31 32 33 # S.C. 指出, 通过下边的命令可以省去for循环. 34 # efax -d /dev/ttyS3 -o1 -t T$1 $2.0* 35 # 但这并不十分有讲解意义[嘿嘿]. 36 37 exit 0while这种结构在循环的开头判断条件是否满足,如果条件一直满足,那就一直循环下去(0为退出码[exitstatus]).与for 循环的区别是,这种结构适合用在循环次数未知的情况下.while [condition]do command... done 和for循环一样,如果想把do和条件放到同一行上还是需要一个;.while [condition] ; do 注意一下某种特定的while循环,比如getopts结构,好像和这里所介绍的模版有点脱节.例子 10-14. 简单的while循环 1 #!/bin/bash 2 3 var00 4 LIMIT10 5 6 while [ $var0 -lt $LIMIT ] 7 do 8 echo -n $var0 # -n 将会阻止产生新行. 9 # ^ 空格,数字之间的分隔. 10 11 var0expr $var0 1 # var0$(($var01)) 也可以. 12 # var0$((var0 1)) 也可以. 13 # let var0 1 也可以. 14 done # 使用其他的方法也行. 15 16 echo 17 18 exit 0例子 10-15. 另一个while循环 1 #!/bin/bash 2 3 echo 4 # 等价于: 5 while [ $var1 ! end ] # while test $var1 ! end 6 do 7 echo Input variable #1 (end to exit) 8 read var1 # 为什么不使用read $var1? 9 echo variable #1 $var1 # 因为包含#字符,所以需要 . . . 10 # 如果输入为end,那么就在这里打印. 11 # 不在这里判断结束,在循环顶判断. 12 echo 13 done 14 15 exit 0一个while循环可以有多个判断条件,但是只有最后一个才能决定是否退出循环.然而这需要一种有点不同的循环语法.例子 10-16. 多条件的while循环 1 #!/bin/bash 2 3 var1unset 4 previous$var1 5 6 while echo previous-variable $previous 7 echo 8 previous$var1 9 [ $var1 ! end ] # 记录之前的$var1. 10 # 这个while循环中有4个条件, 但是只有最后一个能控制循环. 11 # 退出状态由第4个条件决定. 12 do 13 echo Input variable #1 (end to exit) 14 read var1 15 echo variable #1 $var1 16 done 17 18 # 尝试理解这个脚本的运行过程. 19 # 这里还是有点小技巧的. 20 21 exit 0与for循环一样,while循环也可通过(())来使用C风格语法.(见例子9-30).例子 10-17. C风格的while循环 1 #!/bin/bash 2 # wh-loopc.sh: 循环10次的while循环. 3 4 LIMIT10 5 a1 6 7 while [ $a -le $LIMIT ] 8 do 9 echo -n $a 10 let a1 11 done # 到目前为止都没什么令人惊奇的地方. 12 13 echo; echo 14 15 # 16 17 # 现在, 重复C风格的语法. 18 19 ((a 1)) # a1 20 # 双圆括号允许赋值两边的空格,就像C语言一样. 21 22 while (( a LIMIT )) # 双圆括号, 变量前边没有$. 23 do 24 echo -n $a 25 ((a 1)) # let a1 26 # Yes, 看到了吧. 27 # 双圆括号允许像C风格的语法一样增加变量的值. 28 done 29 30 echo 31 32 # 现在,C程序员可以在Bash中找到回家的感觉了吧. 33 34 exit 0while 循环的stdin可以用来重定向到文件.whild循环的stdin支持管道.until这个结构在循环的顶部判断条件,并且如果条件一直为false那就一直循环下去.(与while相反).until [condition-is-true]do command... done 注意: until循环的判断在循环的顶部,这与某些编程语言是不同的.与for循环一样,如果想把do和条件放在一行里,就使用;.until [condition-is-true] ; do 例子 10-18. until循环 1 #!/bin/bash 2 3 END_CONDITIONend 4 5 until [ $var1 $END_CONDITION ] 6 # 在循环的顶部判断条件. 7 do 8 echo Input variable #1 9 echo ($END_CONDITION to exit) 10 read var1 11 echo variable #1 $var1 12 echo 13 done 14 15 exit 0转自 shell在线中文手册http://manual.51yip.com/shell/ 转载于:https://blog.51cto.com/1362336072/1883295