Shell编程之while循环和until循环

时光总嘲笑我的痴心妄想 提交于 2020-02-14 08:32:42

一、当型和直到型循环

1.while循环语句

while < 条件表达式 >
do
    指令...
done

while循环执行流程对应的逻辑图

2.until循环语句

until < 条件表达式 >
do
    指令...
done

until会在条件表达式不成立时,进入循环体执行指令。

3.基本范例

(1)每隔2秒输出一次系统负载

[root@codis-178 ~]# cat 10_1.sh 
#!/bin/bash
while true
do
    uptime
    sleep 2
done
[root@codis-178 ~]# sh 10_1.sh 
 13:59:41 up 251 days, 22:33,  1 user,  load average: 0.02, 0.03, 0.00
 13:59:43 up 251 days, 22:33,  1 user,  load average: 0.02, 0.03, 0.00
 13:59:45 up 251 days, 22:33,  1 user,  load average: 0.02, 0.03, 0.00
 13:59:47 up 251 days, 22:33,  1 user,  load average: 0.02, 0.03, 0.00

(2)防止脚本执行中断的办法
1)使用&,在后台运行
2)使用nohup加&,在后台运行
3)利用screen保持会话,然后再执行命令或脚本

补充;
strace:跟踪一个进程的系统调用情况
ltrace:跟踪进程调用库函数的情况

(3)while循环竖向打印54321

[root@codis-178 ~]# cat 10_2.sh 
#!/bin/bash
i=5
while ((i>0))
do
    echo "$i"
    ((i--))
done
[root@codis-178 ~]# sh 10_2.sh 
5
4
3
2
1

(4)计算1加到100之和

[root@codis-178 ~]# cat 10_3.sh 
#!/bin/bash
i=1
sum=0
while ((i<=100))
do
    ((sum=sum+i))
    ((i++))
done
[ "$sum" -ne 0 ] && printf "totalsum is:$sum\n"
[root@codis-178 ~]# sh 10_3.sh 
totalsum is:5050

(5)猜数字,系统随机生成一个数字(1~60),让用户输入所猜数字,判断是否正确

[root@codis-178 ~]# cat 10_4.sh
#!/bin/bash
total=0
export LANG="zh_CN.UTF-8"
NUM=$((RANDOM%61))

echo "当前苹果的价格是每斤 $NUM 元"
echo "============================"
usleep 1000000
clear

echo "这苹果多少钱一斤啊?请猜0~60的数字"

apple(){
    read -p "请输入你的价格:" PRICE
    expr $PRICE + 1 &>/dev/null
    if [ $? -ne 0 ];then
        echo "快猜数字!"
        apple
    fi
}
guess(){
    ((total++))
    if [ $PRICE -eq $NUM ]
        then
            echo "猜对了"
            if [ $total -le 3 ];then
                echo "已经猜 $total 次了!"
            elif [ $total -gt 3 -a $toatl -le 6 ];then
                echo "已经猜 $total 次了!"
            elif [ $total -gt 6 ];then
                echo "已经猜 $total 次了!有点多!"
            fi
            exit 0
    elif [ $PRICE -gt $NUM ];then
        echo "猜高了!"
        apple
    elif [ $PRICE -lt $NUM ];then
        echo "猜低了!"
        apple
    fi
}
main(){
    apple
    while true
    do
        guess
    done
}
main

[root@codis-178 ~]# sh 10_4.sh 
当前苹果的价格是每斤 30 元
============================
这苹果多少钱一斤啊?请猜0~60的数字
请输入你的价格:40
猜高了!
请输入你的价格:25
猜低了!
请输入你的价格:30
猜对了
已经猜 3 次了!

(6)手机充值10元,每发一条短信花费1.5元,当余额低于1.5元时不能再发短信

[root@codis-178 ~]# cat 10_5.sh
#!/bin/bash
export LANG="zh_CN.UTF-8"
sum=15
msg_fee=2
msg_count=0

menu(){
    cat <<END
当前余额为 ${sum} 分,每条短信需要 ${msg_fee} 分
=================================
    1. 充值
    2. 发消息
    3. 退出
================================
END
}

recharge(){
    read -p "请输入充值金额:" money
    expr $money + 1 &>/dev/null
    if [ $? -ne 0 ];then
        echo "then money your input is error,must be int."
    else
        sum=$(($sum+$money))
        echo "当前余额为:$sum"
    fi
}

sendInfo(){
    if [ ${sum} -lt ${msg_fee} ];then
        printf "余额不足:$sum,请充值。\n"
    else
        while true
        do
            read -p "请输入短信内容:" msg
            sum=$(($sum-$msg_fee))
            printf "发送 $msg successfully!\n"
            printf "当前余额:$sum\n"
            if [ $sum -lt $msg_fee ];then
                printf "余额不足,剩余 $sum分\n"
                return 1
            fi
        done
    fi
}

main(){
    while true
    do
        menu
        read -p "请输入数字选择:" men
        case "$men" in
            1)
                recharge
                ;;
            2)
                sendInfo
                ;;
            3)
                exit 1
                ;;
            *)
                printf "选择错误,必须是{1|2|3}\n"
        esac
    done
}
main

4.企业应用

(1)监控网站,每隔10秒确定一次网站是否正常

[root@codis-178 ~]# cat 10_6.sh 
#!/bin/bash
. /etc/init.d/functions
check_count=0
url_list=(
    http://www.baidu.com
    http://www.anzhi.com
    http://www.163.com
)
function wait(){
    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 ${#url_list[*]}`; i++))
    do
        wget -o /dev/null -T 3 --tries=1 --spider ${url_list[$i]} >/dev/null 2>&1
        if [ $? -eq 0 ];then
            action "${url_list[$i]}" /bin/true
        else
            action "${url_list[$i]}" /bin/false
        fi
    done
    ((check_count++))
}
main(){
    while true
    do
        check_url
        echo "-------check count:${check_count}--------"
        sleep 5
    done
}
main

[root@codis-178 ~]# sh 10_6.sh 
3秒后,执行检查URL操作。...
http://www.baidu.com                                       [  OK  ]
http://www.anzhi.com                                       [  OK  ]
http://www.163.com                                         [  OK  ]
-------check count:1--------
3秒后,执行检查URL操作。...
http://www.baidu.com                                       [  OK  ]
http://www.anzhi.com                                       [  OK  ]
http://www.163.com                                         [  OK  ]
-------check count:2--------

(2)分析Apache日志,把日志中每行的访问字节数对应的字段数字相加,计算总的访问量。

[root@codis-178 ~]# cat 10_7.sh
#!/bin/bash
sum=0
exec <$1  #将参数$1输入重定向给exec
while read line
do
    size=`echo $line|awk '{print $10}'`
    expr $size + 1 &>/dev/null
    if [ $? -ne 0 ];then
        continue
    fi
    ((sum=sum+$size))
done
echo "${1}:total:${sum}bytes = `echo $((${sum}/1024))`KB}"

一条命令完成

awk '{print $10}' access.log |grep -v "-"|awk '{sum+=$1}END{print sum}'

5.按行读文件的方法总结

(1)exec

exec <FILE
sum=0
while read line
do
    cmd
done

(2)cat

cat FILE|while read line
do
    cmd
done

(3)在while循环结尾

while read line
do
    cmd
done < FILE

6.实战应用

根据Web日志或系统网络连接数,监控某个IP的并发连接数,若短时间内PV达到100,即调用防火墙命令封掉对应的IP。
(1)按日志分析

[root@codis-178 ~]# cat 10_8.sh
#!/bin/bash
file=$1
while true
do
    awk '{print $1}' $1|grep -v "^$"|sort|uniq -c > /tmp/tmp.log
    exec </tmp/tmp.log
    while read line
    do
        ip=`echo $line|awk '{print $2}'`
        count=`echo $line|awk '{print $1}'`
        if [ $count -gt 500 ] && [ `iptables -L -n|grep "$ip"|wc -l` -lt 1 ];then
            iptables -I INPUT -s $ip -j DROP
            echo "$line is dropped" >>/tmp/droplist_$(date +%F).log
        fi
    done
    sleep 10
done

(2)按TCP请求

[root@codis-178 ~]# cat 10_9.sh
#!/bin/bash
file=$1
JudgeExt(){
    if expr "$1" : ".*\.log" &>/dev/null
        then
            :
    else
        echo $"usage:$0 xxx.log"
        exit 1
    fi
}
IpCount(){
    grep "ESTABLISHED" $1 |awk -F "[ :]+" '{ ++S[$(NF-3)]}END {for(key in S) print S[key], key}'|sort -rn -k1|head -5 >/tmp/tmp.log
}
ipt(){
    local ip=$1
    if [ `iptables -L -n|grep "$ip"|wc -l` -lt 1 ];then
        iptables -I INPUT -s $ip -j DROP
        echo "$line is dropped" >>/tmp/droplist_$(date +%F).log
    fi
}
main(){
    JudgeExt $file
    while true
    do
        IpCount $file
        while read line
        do
            ip=`echo $line|awk '{print $2}'`
            count=`echo $line|awk '{print $1}'`
            if [ $count -gt 3 ];then
                ipt $ip
            fi
        done</tmp/tmp.log
    done
}
main
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!