shell 12 --- 循環控制及狀態返回值(break、continue、exit、return)
本文介紹幾個特殊的命令:
break(循環控制)、continue(循環控制)、exit(退出腳本)、return(退出函數)。
12.1 break、continue、exit、return的區別和對比
在上述命令中,break、continue在條件語句及循環語句(for、while、if等)中用於控制程序的走向;
而exit則用於終止所有語句並退出當前腳本,除此之外,exit還可以返回上一次程序或命令的執行狀態值給當前Shell;
return類似於exit,只不過return僅用於在函數內部返回函數執行的狀態值。
關於這幾個命令的基本說明如表12-1所示。
| 命令 | 說明 |
|---|---|
| break n | 如果省略n,則表示跳出整個循環,n便是跳出循環的層數 |
| continue n | 如果省略n,則表示跳過本次循環,忽略本次循環的剩余代碼 進入循環的提一次循環。n表示退到第幾層繼續循環 |
| exit n | 退出當前shell程序,n為上一次程序執行的狀態返回值。 n也可以省略,在下一個shell例可通過"$?"接收exit n的返回值 |
| return n | 用於在函數里作為函數的返回值,以判斷函數執行是否正確。 在下一個shell里可通過"$?"接收return n的值 |
12.2 break、continue、exit功能執行流程圖
為了更清晰地了解上述命令的區別,下面特別畫了邏輯圖,方便大家理解。
這里以while循環和for循環為例來說明。
12.2.1 break功能的執行流程邏輯圖
在循環中break功能的執行流程邏輯圖如圖12-1所示。

12.2.2 continue功能的執行流程邏輯圖
在循環中continue功能的執行流程邏輯圖如圖12-2所示。

12.2.3 exit功能的執行流程邏輯圖
在循環中exit功能的執行流程邏輯圖如圖12-3所示。

12.3 break、continue、exit、return命令的基礎示例
下面是與break、continue、exit、return相關的示例。
[root@zabbix 0513]# cat test.sh
#!/bin/bash
if [ $# -ne 1 ];then
echo $"usage: $0 {break|continue|exit|return}"
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"
}
test $*
func_ret=$?
if [ `echo $*|grep return|wc -l` -eq 1 ];then
echo "return's exit status: $func_ret"
fi
echo "OK"
12.3.1 break功能測試說明
傳入break執行結果:
[root@zabbix 0513]# sh test.sh break
0
1
2
I am in func === 傳入break時,退出test函數,繼續順序執行test函數以下的
OK
說明:
根據結果可以看到,i等於3及以后的循環沒有被執行,但循環外的echo執行了,
執行到break時跳出了if及外層的for循環語句,然后執行for循環外部done后面的打印ok的語句。
12.3.2 continue功能測試說明
[root@zabbix 0513]# sh test.sh continue
0
1
2 ===下面沒有3,直接跳過了
4
5
I am in func
OK
說明:
可以看到,只有i等於3這層循環沒有被執行,其他循環全部執行了,
循環外的echo也執行了,說明執行到continue時,終止了本次循環,
而繼續下一次的循環,直到循環正常結束,接着繼續執行了循環外面的所有語句。
12.3.3 exit功能測試說明
傳入exit 119命令的執行結果為:
[root@zabbix 0513]# sh break.sh "exit 119"
0
1
2 === 直接退出shell
[root@zabbix 0513]# echo $?
119 === 返回了119,即傳入的值
說明:
當進入循環里的if語句后遇到"exit 119"時,立刻退出程序,不但循環體3后面的數字沒有輸出,
而且for循環體done外的echo和函數外的ok也沒有輸出,就直接退出了程序。
另外,因為程序退出時指定了119, 所以執行腳本后獲取"$?"的返回值時,
就返回了"exit 119"后面的119這個數字到當前的Shell。
12.3.4 return功能測試說明
傳入"return 119"命令的執行結果為:
[root@zabbix 0513]# sh break.sh "return 119"
0
1
2
return's exit status: 119
OK
說明:
當進入循環里的if語句后遇到return 119,就沒有打印3以下的數字,
說明return跳出了循環體,程序也沒有執行for循環體done外的echo命令,
而是直接執行了函數test外的if語句及打印ok的命令,可見return的作用是退出當前函數。
同時,return將數字119作為函數的執行狀態值返還給函數體外,
執行腳本后打印返回值是0,因為程序的最后一行是打印ok的命令,執行是成功的。
12.4 循環控制及狀態返回值企業案例
范例12-2:開發Shell腳本實現為服務器臨時配置多個IP,並且可以隨時撤銷配置的所有IP。
IP的地址范圍為:10.0.2.1~10.0.2.16,其中10.0.2.10不能配置。
本題主要用於考察continue、return、exit的綜合應用,請讀者細細品味。
首先,給網卡配置額外的IP。以下介紹兩種配置IP的命令(ifconfig/ip)。
12.4.1 臨時配置多個ip的方法
1)使用ifconfig配置別名IP的方法:
ifconfig eth0:0 10.0.0.10/24 up ==> 添加ip
ifconfig eth0:0 10.0.0.10/24 down ==> 刪除ip
2)使用IP配置輔助IP的方法:
ip addr add 10.0.0.12 dev eth0 lable eth0:0
ip addr del 10.0.0.12 dev eth0 lable eth0:0
3)然后批量配置IP。
要求IP地址的取值范圍為:10.0.2.1~10.0.2.16,其中10.0.2.10不能配置。
for ip in {1..16}
do
if [ $ip -eq 10 ];then
continue
else
ifconfig ens33:$ip 10.0.0.${ip}/24 up
fi
done
4)shell 腳本實現
[root@zabbix 0513]# cat add_ip.sh
#!/bin/bash
[ -f /etc/init.d/functions ]&& . /etc/init.d/functions
RETVAL=0
function operation(){
if [ "$1" == "del" ];then
list=`echo {16..1}`
else
list=`echo {1..16}`
fi
for ip in $list
do
if [ $ip -eq 10 ];then
continue
fi
ip addr $1 10.0.0.${ip}/24 dev eth0 lable eth0:$ip &>/dev/null
RETVAL=$?
if [ $RETVAL -eq 0 ];then
action "$1 $ip" /bin/true
else
action "$1 $ip" /bin/false
fi
done
return $RETVAL
}
case "$1" in
start)
operation add
RETVAL=$?
;;
stop)
operation del
RETVAL=$?
;;
restart)
operation del
sleep 2
operation add
RETVAL=$?
;;
*)
printf $"USAGE: $0 {start|stop|restart}"
esac
exit $RETVAL
12.4.2 RANDOM隨機數md5比對
范例12-4:
已知下面的字符串是通過將RANDOM隨機數采用md5sum加密后任意取出連續10位的結果,
請破解這些字符串對應的md5sum前的數字?
解題思路:本題原本是想考察break的用法,但是還考察了RANDOM隨機數的范圍,
該范圍是0~32767,請務必記住。要想解決本題,首先要將0~32767范圍內的所有數字通過md5sum加密,
並把加密后的字符串和加密前的數字對應地寫到日志里。然后將題中給出的加密后的字符串4fe8bf20ed和指紋庫里的所有使用md5sum加密后的字符串
進行比對(grep最佳),如果匹配,則把對應的行及對應的數字輸出。
首先將0~32767范圍內的所有數字通過md5sum加密,
並把加密后的字符串和加密前的數字對應地寫到日志里,實現腳本如下:
[root@zabbix 0514]# cat random.sh
#!/bin/bash
for n in {0..327767}
do
echo "`echo $n|md5sum` $n" >>/tmp/finger.txt
done
# [root@zabbix 0514]# grep -w 722 /tmp/finger.txt
# f136b51b96a2a2ccefab9b82f1182d91 - 722
md5char="f136b51b96a2a2ccefab9b82f1182d91"
while read line
do
if [ `echo $line|grep "$md5char" |wc -l` -eq 1 ];then
echo $line
break
fi
done < /tmp/finger.txt
[root@zabbix 0514]# sh random.sh
f136b51b96a2a2ccefab9b82f1182d91 - 722
