循環控制及狀態返回值

1.break、continue、exit、return的區別

break、continue在條件語句及循環語句(for、while、if等)中用於控制程序的走向;而exit則用於終止全部語句並退出當前腳本了,除此以外exit還能夠將上一次程序或命令的執行狀態的返回值給當前shell;ruturn和exit相似,只不過return用於在函數內部返回函數執行的狀態值。基本說明以下圖所示:mysql

循環控制及狀態返回值

2.break、continue、exit功能執行流程圖

以while循環和for循環舉例。break功能執行流程圖以下圖所示:sql

循環控制及狀態返回值

continue功能執行流程圖以下所示:shell

循環控制及狀態返回值

exit功能的執行流程圖以下圖所示:apache

循環控制及狀態返回值

3.break、continue、exit、return命令示例

範例:經過下面的腳本驗證break、continue、exit、return命令的功能bash

[root@shellbiancheng jiaobenlianxi]# cat xunhuankongzhi.sh
#!/bin/bash
if [ $# -ne 1 ];then   若是參數不爲1執行if語句裏面的echo命令
echo $"Usage:$0 {break|continue|exit|return}" 分別傳入4個命令做爲參數
exit 1  退出腳本
fi
function test(){  定義測試函數
for((i=0;i<=5;i++))
do
if [ $i -eq 3 ];then
$*;         用於接收函數體外的參數
fi
echo $i
done
echo "I am in func." 執行for循環外的輸出提示
}
test $*    調用test函數,實現腳本傳參
func_ret=$?    接收並測試函數的返回值
if [ `echo $*|grep return|wc -l` -eq 1 ] 若是傳參是return就執行if語句中echo命令
then
echo "return's exit status:$func_ret" 若是傳參是return,打印函數的返回值
fi
echo "ok" 函數體外的輸出提示

(1)驗證break命令,執行結果以下服務器

[root@shellbiancheng jiaobenlianxi]# sh xunhuankongzhi.sh 
Usage:xunhuankongzhi.sh {break|continue|exit|return}
[root@shellbiancheng jiaobenlianxi]# sh xunhuankongzhi.sh break
0
1
2
I am in func.
ok

從結果能夠看出,當i=3時執行了break命令循環中之後的命令沒有執行,可是循環外的echo命令執行了,執行到break時跳出了if以及for循環,而後執行test函數中的echo命令以及test函數體外的echo命令。curl

(2)驗證continue命令,執行結果以下ide

[root@shellbiancheng jiaobenlianxi]# sh xunhuankongzhi.sh continue
0
1
2
4
5
I am in func.
ok

能夠看出當i=3時,這層循環沒有被執行,其餘循環所有還行了,循環外的echo也執行了,這說明執行到continue時,終止(跳出)了本次循環,而繼續下一次的循環,直到循環正常結束,接着執行循環外的全部語句。函數

(3)驗證exit命令,在下一個shell裏能夠用「$?」接收exit n的返回值,執行結果以下:測試

[root@shellbiancheng jiaobenlianxi]# sh xunhuankongzhi.sh "exit 100"
0
1
2
[root@shellbiancheng jiaobenlianxi]# echo $?
100

從結果能夠看出,當進入循環裏的if語句後遇到「exit 100」時,馬上腿出程序;不但循環體3後面的數字沒有輸出,並且for循環體done外的echo和函數外的ok也沒有輸出,就直接退出了程序。另外由於程序退出時指定100,因此執行腳本後用「$?」獲取返回值就返回了100。

(4)驗證return命令,執行結果以下

[root@shellbiancheng jiaobenlianxi]# sh xunhuankongzhi.sh "return 100"
0
1
2
return's exit status:100
ok
[root@shellbiancheng jiaobenlianxi]# echo $?
0

當執行到return 100時,就沒有執行3一下的數字,說明return跳出了循環體、for循環體done後echo也沒有執行而是直接執行後函數體外面的內容,能夠看出return的做用是退出當前函數。同return將數字100做爲函數的返回值返回給函數體外,返回值$func_ret的值等於100。之因此執行腳本後打印的返回值是0,是由於程序最後打印的是echo命令,執行腳本成功後的返回值就是0。

4.案例

(1)案例1:開發shell腳本實現爲服務器臨時配置多個IP,而且不能臨時撤銷配置的全部IP,IP地址範圍爲:192.168.136.220-192.168.136.225,其中192.168.136.223不能設置。

使用ifconfig給IP設置別名:

ifconfig eth0:0 192.168.136.224/24 up  添加別名
ifconfig eth0:0 192.168.136.224/24 down  刪除別名

使用ip addr給IP設置別名:

ip addr add 192.168.136.224/24 dev eth0 label eth0:0  添加別名
ip addr del 192.168.136.224/24 dev eth0 label eth0:0  刪除別名

代碼以下:

[root@shellbiancheng jiaobenlianxi]# cat ipalias.sh  
#!/bin/bash
[ -f "/etc/init.d/functions" ] && . /etc/init.d/functions
RETVAL=0
export PATH="/usr/local/mysql/bin:/usr/local/sbin:/usr/local/bin:/sbin:/bin:/usr/sbin:/usr/bin:/usr/local/curl/bin:/root/bin"

function add(){

for ip in {220..225}
do
if [ $ip -eq 223 ];then
continue
fi
ip addr add 192.168.136.$ip/24 dev eth0 label eth0:$ip &>/dev/null
RETVAL=$?
if [ $RETVAL -eq 0 ];then
action "add $ip" /bin/true
else
action "add $ip" /bin/false
fi
done
return $RETVAL
}

function del(){
for ip in {225..220}
do  
if [ $ip -eq 223 ];then
continue 
fi
ip addr del 192.168.136.$ip/24 dev eth0 label eth0:$ip &>/dev/null
RETVAL=$?
if [ $RETVAL -eq 0 ];then
action "del $ip" /bin/true
else
action "del $ip" /bin/false
fi
done
return $RETVAL

}

function main(){

case "$1" in
start)
  add
  RETVAL=$?
  ;;
 stop)
 del
 RETVAL=$?
 ;;
  restart)
 del
 sleep 2
 add
 RETVAL=$?  
 ;;
*)
 printf "Usage:$0 {start|stop|restart}\n"
esac

}

main $1
exit $RETVAL

(2)案例2:分析apache訪問日誌,把日誌中每行的訪問字節數對應的字段數相加,計算出訪問量。用while循環實現。朋友們作測試的時候若是沒有訪問日誌能夠去網上下載一個訪問日誌。

[root@shellbiancheng jiaobenlianxi]# cat apachefangwen.sh 
#!/bin/bash
sum=0
RETVAL=0
byte="1024"
b="/home/linzhongniao/tools/access_2013_05_30.log"
exec <$b
while read line 
do
   size=`echo  $line|awk '{print $10}'|grep -v "-"|tr '\r' ' '`  
   expr $size + 1 &>/dev/null
   if [ $? -ne $RETVAL ];then
continue
   fi
   ((sum+=size))
done
echo "${b}:total:${sum}bytes = `expr ${sum} / $byte`KB"

(3)案例3:破解用RANDOM生成的隨機數「0~32767」範圍內的全部數字用md5sum加密以前的數字?

解決過程,先將0-32767範圍內的全部數字經過md5sum加密,並把加密後的字符串和加密前的數字對應的寫入到日誌文件中,腳本以下:

[root@shellbiancheng jiaobenlianxi]# cat RANDOM.sh 
#!/bin/bash
for n in {0..32767}
do
echo "`echo $n|md5sum` $n" >>/tmp/zhiwen1.log

done

查看執行結果:

[root@shellbiancheng jiaobenlianxi]# head /tmp/zhiwen.log 
897316929176464ebc9ad085f31e7284  - 0
b026324c6904b2a9cb4b88d6d61c81d1  - 1
26ab0db90d72e28ad0ba1e22ee510510  - 2
6d7fce9fee471194aa8b5b6e47267f03  - 3
48a24b70a0b376535542b996af517398  - 4
1dcca23355272056f04fe8bf20edfce0  - 5
9ae0ea9e3c9c6e1b9b6252c8395efdc1  - 6
84bc3da1b3e33a18e8d5e1bdd7a18d7a  - 7
c30f7472766d25af1dc80b3ffc9a58c7  - 8
7c5aba41f53293b712fd86d08ed5b36e  - 9

解密加密後的字符串3ae5dc2d,和指紋庫裏面的全部使用md5sum加密後的字符串進行比對,若是匹配輸出加密以前的數字。

[root@shellbiancheng jiaobenlianxi]# cat md5pojie.sh   
#!/bin/bash
#for n in {0..32767}
#do

#   echo "`echo $n|md5sum` $n" >>/tmp/zhiwen.log
#done

exec </tmp/zhiwen.log
md5char="3ae5dc2d"
while read line
do
  if [ `echo "$line"|grep "$md5char"|wc -l` -eq 1 ];then
  echo "$line"
  break
  fi

done

執行結果:3ae5dc2d加密以前的數字爲10000

[root@shellbiancheng jiaobenlianxi]# sh md5pojie.sh 
154773ae5dc2d36d8b9747e5d3dbfc36  - 10000