shell编程 12 --- 循环控制及状态返回值(break、continue、exit、return)

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所示。

shell编程 12 --- 循环控制及状态返回值(break、continue、exit、return)

12.2.2 continue功能的执行流程逻辑图

在循环中continue功能的执行流程逻辑图如图12-2所示。

shell编程 12 --- 循环控制及状态返回值(break、continue、exit、return)

12.2.3 exit功能的执行流程逻辑图

在循环中exit功能的执行流程逻辑图如图12-3所示。

shell编程 12 --- 循环控制及状态返回值(break、continue、exit、return)

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

shell编程 12 --- 循环控制及状态返回值(break、continue、exit、return)

上一篇:Linux中,xargs命令的使用


下一篇:使用 Linux 的 strace 命令跟踪/调试程序的常用选项