大师网-带你快速走向大师之路 解决你在学习过程中的疑惑,带你快速进入大师之门。节省时间,提升效率

shell基础(五)for循环及循环终止命令

一、循环终止的特殊命令

break、exit、continue、return的区别

break n:如果省略n,则表示跳出整个循环、n表示跳出循环的层数
continue n:如果省略n,则表示跳出本次循环,忽略本次循环的剩余代码,进入循环的下一个循环。n表示退到第n层继续循环
exit n:退出当前shell,n为上一次程序执行的状态返回值,n也可以省略,在下一个shell里可通过"$?"接收exit n 的n值
return n :用于在函数里作为函数值返回,以判断函数执行是否正确,在下一个shell里可通过"$?"接收exit n 的n值

例一:

#!/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
        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"

效果如图:

[root@mycentos shell]# sh 2.sh break
0
1
2
I am in func  #跳出for循环,后继续执行函数后面的代码
ok        #执行脚本后面的代码

[root@mycentos shell]# sh 2.sh continue
0
1
2
4
I am in func   #将跳出for循环中本次循环,继续执行下次循环
ok             #脚本后面的内容继续执行

[root@mycentos shell]# sh 2.sh "exit 119"
0
1
2  #直接跳出脚本,函数和脚本后面的内容不执行
[root@mycentos shell]# echo $?
119     退出程序时指定了"119",则执行脚本后获取"$?"的返回值就返回了"119",给当前的shell

[root@mycentos shell]# sh 2.sh "return  119"
0
1
2   #return 直接退出当前函数
return's exit status:119  #将119返回到了函数的外部脚本
ok
[root@mycentos shell]# echo $? 
0            #执行脚本后的返回值为0,因为脚本中最后一条命令"ok"打印成功

实战一:

开发shell脚本实现服务器临时配置多个IP,并且可以随时撤销配置的所有IP.IP的地址范围为:10.0.2.1~10.0.2.16,其中10.0.2.10不能配置

预备知识:
一、给网卡配置额外IP的两种方式
1.)ifconfig配置别名IP的方式
ifconfig eth0:0 10.0.2.10/24 up #添加IP
ifconfig eth0:0 10.0.2.10/24 down #删除IP
2.)使用ip配置辅助IP的方式:
ip addr add 10.0.2.11/24 dev eth0 label eth0:0 #添加ip
ip addr del 10.0.2.11/24 dev eth0 label eth0:0 #删除ip

简略版:
#!/bin/bash
for num in $(seq 16)
do
        if [ $num -eq 10 ];then
                continue
        else
                #ip addr add  10.0.2.$num/24 dev eth0 label eth0:$num  <==这个也可以
                ifconfig eth0:$num 10.0.2.$num/24 down
        fi
done
简单版本:
#!/bin/bash
[ -f /etc/init.d/functions ]&& . /etc/init.d/functions
RETVAL=0
function add(){
        for ip in {1..16}
        do
                if [ $ip -eq 10 ];then
                        continue
                else
                        ifconfig eth0:$ip 10.0.2.${ip}/24 up
                        RETVAL=$?
                        if [ $RETVAL -eq 0 ];then
                                action "add $ip" /bin/true
                        else
                                action "add $ip" /bin/false
                        fi
                fi
        done
        return $RETVAL
}
function del(){
        for ip in {1..16}
        do
                if [ $ip -eq 10 ];then
                        continue
                else
                        ifconfig eth0:$ip 10.0.2.${ip}/24 down
                        RETVAL=$?
                        if [ $RETVAL -eq 0 ];then
                                action "del $ip" /bin/true
                        else
                                action "del $ip" /bin/false
                        fi
                fi 
        done
        return $RETVAL
}
case "$1" in
        start)
                add
                RETVAL=$?
                ;;
        stop)
                del
                RETVAL=$?
                ;;
        restart)
                del
                sleep 2
                add
                RETVAL=$?
                ;;
        *)
                printf $"usage:$0 {start|stop|restart}"
esac
exit $RETVAL
注:
    一、此版本代码冗余多,可以将冗余代码组合
去除代码冗余版:
#!/bin/bash
[ -f /etc/init.d/functions ]&& . /etc/init.d/functions
RETVAL=0
function op(){
        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   #跳出此次循环
                else
                        ip addr $1 10.0.2.$ip/24 dev eth0 label eth0:$ip &>/dev/null
                        RETVAL=$?
                        if [ $RETVAL -eq 0 ];then
                                action "$1 $ip" /bin/true
                        else
                                action "$1 $ip" /bin/false
                        fi
                fi
         done
        return $RETVAL
}
case "$1" in
        start)
                op add  #注意传参到op函数中去
                RETVAL=$?
                ;;
        stop)
                op del
                RETVAL=$?
                ;;
        restart)
                op del
                sleep 2
                op add
                RETVAL=$?
                ;;
        *)
                printf $"usage:$0 {start|stop|restart}"
esac
exit $RETVAL

效果如下:

[root@mycentos ~]# sh 1.sh start
add 1                                                      [  OK  ]
add 2                                                      [  OK  ]
add 3                                                      [  OK  ]
add 4                                                      [  OK  ]
add 5                                                      [  OK  ]
add 6                                                      [  OK  ]
add 7                                                      [  OK  ]
add 8                                                      [  OK  ]
add 9                                                      [  OK  ]
add 11                                                     [  OK  ]
add 12                                                     [  OK  ]
add 13                                                     [  OK  ]
add 14                                                     [  OK  ]
add 15                                                     [  OK  ]
add 16                                                     [  OK  ]
使用ifconfig可查看eth0的虚拟ip

实战二:

已知下面字符串是将RANDOM随机数采用md5sum加密后任意取出的连续10位结果,请破解这些字符串对应的md5sum前对的字符串的数字?
"4fe8bf20ed"

一、预备知识
RANDOM的范围是:0~32767
二、思路:
1.)先将RANDOM随机的所有可能写成字典
2.)用脚本做密码匹配

1)RANDOM字典的生成
#!/bin/bash
for n in {0..32767}
do
        echo "$(echo $n | md5sum) : $n" >> zhiwen.txt
done
echo "ok"
2)匹配密码
#!/bin/bash

md5char="4fe8bf20ed" #要匹配的字符串

while read line #变量是line
do 
        if [ $(echo $line | grep $md5char | wc -l) -eq 1 ];then
                echo $line 
                break  #匹配到后就退出程序

        fi

done<zhiwen.txt #按行读取字典
将上述代码合并
#!/bin/bash

>zidian.txt #清空字典文件
for n in {0..32767}
do
        echo "$(echo $n |md5sum) : $n" >>zidian.txt  #此处不能是">"
done
echo "input ok"

md5char="4fe8bf20ed" #要破解密码


while read line
do
        if [ $(echo $line | grep $md5char |wc -l ) -eq 1 ];then 
                echo $line
                break
        fi

done<zidian.txt

效果如图:

[root@mycentos shell]# sh 7.sh 
1dcca23355272056f04fe8bf20edfce0 - : 5

二、数组

数组的操作

1.定义数组:
方式一:用小括号将变量值括起来赋值给数组变量,每个变量之间要用空格进行分格
[root@mycentos shell]# array=(1 2 3)
[root@mycentos shell]# echo ${array[*]}  #打印单个数组元素时用"${数组名[下标]}",当未指定数组下标时,数组的下标将从0开始。
1 2 3
方式二:用小括号将变量括起来,同时1采用键值对的形式赋值
array=([1]=one [2]=two [3]=three)
小括号里对应的数字为数组下标,等号后面的内容为下标对应的数组变量的值。
[root@mycentos shell]# array=([1]=one [2]=twe [3]=three)
[root@mycentos shell]# echo ${array[1]}  
one
[root@mycentos shell]# echo ${array[2]}
twe
[root@mycentos shell]# echo ${array[3]}
three
[root@mycentos shell]# echo ${array[*]}
one twe three
此方式繁琐,不推荐

方法三:动态的定义数组变量,并使用命令的输出结果作为数组内容
array=($(命令))
或
array=(`命令`)

[root@mycentos Desktop]# touch array/{1..3}.txt
[root@mycentos Desktop]# ls -l array/
total 0
-rw-r--r--. 1 root root 0 Nov 15 14:44 1.txt
-rw-r--r--. 1 root root 0 Nov 15 14:44 2.txt
-rw-r--r--. 1 root root 0 Nov 15 14:44 3.txt
[root@mycentos Desktop]# array=($(ls array/))
[root@mycentos Desktop]# echo ${array[*]}
1.txt 2.txt 3.txt
------------------------------------------------------------------------------------------------
2.打印数组长度
echo {#数组名[*]}
数组是特殊的变量,变量子串的知识也试用。
------------------------------------------------------------------------------------------------
3.数组的赋值:
数组名[下标]=值
------------------------------------------------------------------------------------------------
4.数组的删除:
由于数组本质上是变量,则可通过unset 数组[下标]来清除相应的数组元素,如果不带下标,则表示清除整个数组的所有数据。
------------------------------------------------------------------------------------------------
5.数组内容的截取和替换:
[root@mycentos ~]# array=(1 2 3 4 5)
[root@mycentos ~]# echo ${array[*]:1:3}   #从下标为1的元素开始截取3个数组元素
2 3 4
[root@mycentos ~]# array=({a..z})
[root@mycentos ~]# echo ${array[*]}
a b c d e f g h i j k l m n o p q r s t u v w x y z
[root@mycentos ~]# echo ${array[*]:1:2}  #从下标为1的元素开始截取2个数组元素
b c 

[root@mycentos ~]# array=(1 2 3 4 5)
[root@mycentos ~]# echo ${array[*]/1/b}  #把数组的1替换成b,原来数组被修改和sed很像
b 2 3 4 5

替换方法:
${数组名[@或*]/查找字符/替换字符},该操作并不会改变原先数组的内容。

例一:
使用循环批量输出数组的元素

方式一:C语言型打印数组元素
#!/bin/bash
array=(1 2 3 4 5)
for ((i=0;i<${#array[*]};i++))
do
        echo ${array[i]}
done
方式二:
普通循环打印数组元素
#!/bin/bash
array=(1 2 3 4 5)
for n in ${array[*]} #<==${array[*]}表示输出数组的所有元素,相当于列表数组元素
do
        echo $n
done
方式三:
#!/bin/bash
array=(1 2 3 4 5)
i=0
while ((i<${#array[*]}))
do
        echo ${array[i]}
        ((i++))
done

例二:通过竖向列举法定义数组元素批量打印

#!/bin/bash
array=(
oldboy
oldgirl
xiaoming
xiaoqiang
)
for ((i=0;i<${#array[*]};i++))
do
        echo "this is num $i,then content is ${array[$i]}"
done
echo "array len:${#array[*]}"

结果如图:

[root@mycentos arr]# sh 4.sh 
this is num 0,then content is oldboy
this is num 1,then content is oldgirl
this is num 2,then content is xiaoming
this is num 3,then content is xiaoqiang
array len:4

例三:
将命令结果作为数组元素定义并打印

#!/bin/bash
dir=($(ls ./*.txt))
for ((i=0;i<${#dir[*]};i++))
do
        echo "this is NO.$i,filename is ${dir[$i]}"

done

结果如图:

[root@mycentos arr]# sh 5.sh 
this is NO.0,filename is ./1.txt
this is NO.1,filename is ./2.txt
this is NO.2,filename is ./3.txt
this is NO.3,filename is ./4.txt

关于数组的总结:

1).定义:
静态array=(1 2 3)
动态array=($(ls))
2).赋值:array[3]=4
3).打印:${array[*]}或${array[*]}
    数组长度:${#array[@]}或${#array[*]}
    单个元素:${array[i]}
4).循环打印
#!/bin/bash
arr=(
        10.0.0.11
        10.0.0.22
        10.0.0.33
)
#<==C语言循环打印
for ((i=0;i<${#arr[*]};i++))
do
        echo "${arr[i]}"

done
echo '-----------------------------------'
#<==普通循环打印
for n in ${arr[*]}
do
        echo "$n"
done

实战三

利用for循环打印下面这句话不大于6的单词
I am lodboy teacher welcome to oldboy training class

计算变量内容长度方式:
[root@mycentos arr]# char=oldboy
[root@mycentos arr]# echo char | wc -L 6 [root@mycentos arr]# echo{char}
oldboy
[root@mycentos arr]# echo {#char} 6 [root@mycentos arr]# expr lengthchar
6
[root@mycentos arr]# expr char | awk '{print length(0)}'
6

方式一(数组实现):
#!/bin/bash
arr=(I am oldboy teacher welcome to oldboy training class)

for ((i=0;i<${#arr[*]};i++))
do
        #if [ $(expr length ${arr[i]}) -lt 6 ];then
        #       echo ${arr[i]}
        #fi

        if [ ${#arr[i]} -lt 6 ];then
                echo ${arr[i]}
        fi
done

方式二(列表实现):#!/bin/bash
for word in I am oldboy teacher welcome to oldboy training class
do
        if [ ${#word} -lt 6 ];then

                echo $word
        fi

done
方法三(awk循环):
[root@mycentos arr]# char="I am oldboy teacher welcome to oldboy training class"
[root@mycentos arr]# echo $char | awk '{for(i=1;i<=NF;i++) if(length($i)<6)print $i}' 
I
am
to
class

实战四

检测多个网站地址是否正常
要求:
1)使用shell数组的方法实现,检测策略尽量使用模拟用户访问
2)每10秒进行一次全部检测,无法访问的输出报警
3)待检测的地址如下
http://www.baidu.com
http://www.sina.com
http://www.qq.com
http://www.1.com

思路:
一、网站放到数组中
二、编写URL检测脚本,传入数组的元素,即URL
三、组合实现整个案例,编写main的主函数(即执行函数),每隔10秒检查一次

#!/bin/bash

. /etc/init.d/functions


check_count=0

urlArr=(
        http://www.linuxprobe.com
        http://www.sina.com
        http://www.a.co
        http://www.baidu.com
)

function wait(){  #定义倒计数3、2、1函数

        echo -n "3秒后,执行检查URL的操作"
        for ((i=0;i<3;i++))
        do
                echo -n '.';sleep 1
        done
        echo

}
function check_url(){

        wait  #执行倒计时函数
        for ((i=0;i<$(echo ${#urlArr[*]});i++))
        do
                wget -o /dev/null -T 5  --tries=1 --spider  ${urlArr[i]} &>/dev/null

                if [ $? -eq 0 ];then
                        action "${urlArr[i]}" /bin/true
                else
                        action "${urlArr[i]}" /bin/false
                fi
        done
        ((chenk_count++)) #检测次数
}
function main(){

        while true
        do
                check_url
                echo "-------check count:${check_count}-----"
                sleep 1
        done
}
main

效果如图:


未标题-1.gif