1. 程式人生 > >循環控制及狀態返回值

循環控制及狀態返回值

cti 次循環 then echo init.d 代碼 gre return random

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

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

技術分享圖片

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

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

技術分享圖片

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

技術分享圖片

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

技術分享圖片

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

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

[root@shellbiancheng jiaobenlianxi]# cat xunhuankongzhi.sh
#!/bin/bash
if [ $# -ne 1 ];then   如果參數不為執行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命令。

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

[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

循環控制及狀態返回值