shell 脚本变成使用过程中通常需要流程控制,一般情况下是顺序执行,在实际使用过程中根据不同情况需要执行不同命令,这时就用到选择执行比如if、case,有时需要重复执行多次,循环执行比如for、while、until
条件选择执行语句if
单分支 | 双分支 |
if 判断条件;then 条件为真的分支代码 fi |
if 判断条件; then 条件为真的分支代码 else 条件为假的分支代码 fi |
[[email protected] ~]# vim score.sh 1 #!/bin/bash 2 read -p "please input you score :"score 3 if [ $score -eq 100 ];then 4 echo "excellent" 5 elif[ $score -ge 60 ];then 6 echo "keep tring" 7 fi
条件判断语句case
case 变量引用 in PAT1) 分支1 ;; PAT2) 分支2 ;; *) 默认分支 ;; esac |
例:编写脚本/root/bin/yesorno.sh,提示用户输入yes或no,并判断用户输入的是yes还是no,或是其它信息
[[email protected] ~]# cat /bin/yesorno.sh #!/bin/bash read -p "marry me? please answer yes or no: " ANS case $ANS in [Yy][Ee][Ss]|[Yy]) echo "me too" ;; [Nn][Oo]|[Nn]) echo"my heart broken" ;; *) echo"once again" esac
循环执行语句
for循环循环次数事先已知
依次将列表中的元素赋值给“变量名”; 每次赋值后即执行一次循环体; 直到列表中的元素耗尽,循环结束
方法一 | 方法二:特殊格式 |
for 变量名 in 列表;do 循环体 done |
for ((初始化exp1;条件判断exp2;控制变量的修 正表达式exp3)) 循环体 done |
例:编写脚本,提示输入正整数n的值,计算1+2+…+n的总和
方法一: #!/bin/bash read -p "please input positive integer: " n sum=0 for i in `seq 1 $n` do sum=$[$sum+$i] done echo $sum 方法二: [[email protected] ~]# vim sum.sh #!/bin/bash read -p "please input positive integer: " n sum=0 for ((i=1;i<=$n;i++)) do sum=$[$sum+$i] done echo $sum
while循环循环次数事先未知
CONDITION:循环控制条件;进入循环之前,先做一次判断;每一次循环之后会再次做判断;条件为“true”,则执行一次循环;直到条件测试状态为“false”终止循环
因此:CONDTION一般应该有循环控制变量;而此变量的值会在循环体不断地被修正
进入条件:CONDITION为true
退出条件:CONDITION为false
用法一: | 用法二:while循环的特殊用法(遍历文件的每一行) |
while cmd ;do cmdN ... done |
while read line; do 循环体 done < /PATH/FROM/SOMEFILE 注:依次读取/PATH/FROM/SOMEFILE文件中的每一行,且将行赋值给变量line |
例:编写脚本,求100以内所有正奇数之和
[[email protected] ~]# vim score.sh 1 #!/bin/bash 2 sum=0;i=1 3 while ((i<100)) 4 do 5 sum=$[$sum+$i] 6 let i=$[$i+2] 7 done 8 echo "sum=$sum"
例:扫描/etc/passwd文件每一行,如发现GECOS字段为空,则填充用户名和单位电话,并提示该用户的GECOS信息修改成功。
#!/bin/bash while read line ;do comment=`echo $line |cut -d: -f5` username=`echo $line |cut -d: -f1` if [ -z "$comment" ];then chfn -f "$username" $username &> /dev/null chfn -p "0371-61703300" $username &>/dev/null fi done < /app/passwd
until循环有进入条件和退出条件
进入条件: CONDITION 为false
退出条件: CONDITION 为true
until CONDITION; do 循环体 done |
例:编写脚本,求100以内所有正奇数之和
[email protected] ~]# vim score.sh 1 #!/bin/bash 2 sum=0;i=1 3 until ((i>100)) 4 do 5 sum=$[$sum+$i] 6 let i=$[$i+2] 7 done 8 echo "sum=$sum"
select循环语句
select 循环主要用于创建菜单,按数字顺序排列的菜单项将显示在标准错误上,并显示 PS3 提示符,
等待用户输入
select 是个无限循环,因此要记住用 break 命令退出循环,或用 exit 命令终止脚本。也可以按ctrl+c 退出循环
用户输入菜单列表中的某个数字,执行相应的命令
用户输入被保存在内置变量 REPLY 中
select variable in list do 循环体命令 done |
循环控制语句continue
continue [N]:提前结束第N层的本轮循环,而直接进入下一
轮判断;最内层为第1层
while CONDTIITON1; do CMD1 ... if CONDITION2; then continue fi CMDn ... done |
循环控制语句break
break [N]:提前结束第N层循环,最内层为第1层
while CONDTIITON1; do CMD1 ... if CONDITION2; then break fi CMD |
作业:
1、编写脚本,提示请输入网络地址,如192.168.0.0,判断输入的网段中主机在线状态,并统计在线和离线主机各多少
[[email protected] ~]# vim ping.sh #!/bin/bash read -p "please input network (eg:192.168.0.0):" net echo $net |egrep "([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5]).{3}[0-9]|[1-9][ 0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-4]" &> /dev/null if [ $? -eq 0 ];then netip=`echo $net |egrep -o ".*\."` for (( i=1;i<255;i++ ));do { ping -c 1 -w1 $netip$i &>/dev/null if [ $? -eq 0 ];then echo "$netip$i is up " echo "$netip$i" >> /app/${netip}txt; fi }& done else echo "please input correct format" fi
2、编写脚本,实现打印国际象棋棋盘
#!/bin/bash yellow="\033[1;43m \033[0m" red="\033[1;44m \033[0m" for i in {1..8} ; do if [ $[i%2] -eq 0 ] ; then for j in {1..4} ; do echo -en "$yellow$red" done else for j in {1..4} ; do echo -en "$red$yellow" done fi echo done
3、查找连接次数大于10 的拒绝链接
方法一:只能对一个大于十次的链接进行处理 #!/bin/bash checkinterval=30 while true ;do link=`netstat -nt | sed -rn ‘/^tcp/s/.* (.*):.*$/\1/p‘ |sort |uniq -c |sort -nr |head -n 1` linknum=`echo $link |cut -d " " -f1` ip=`echo $link |cut -d " " -f2` [ $linknum -ge 10 ]&& iptables -A INNPUT -s -$ip -j REJECT echo "$ip at `date +‘%F %T‘` is reject " >> /app/checknet.log sleep $checkinterval done 方法二:当有多个大于十次链接都可以进行处理 #!/bin/bash while true ;do link=`netstat -nt | sed -rn ‘/^tcp/s/.* (.*):.*$/\1/p‘ |sort |uniq -c |sort -nr ` echo "$link"|while read fileline ;do linknum=`echo $link |cut -d " " -f1` ip=`echo $link |cut -d " " -f2` if [ $linknum -ge 10 ];then iptables -A INPUT -s -$ip -j REJECT echo "$ip at `date +‘%F %T‘` is reject " >> /app/checknet.log fi done