• Shell编程之while循环和until循环


    一、当型和直到型循环

    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
    "
    [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,请充值。
    "
    	else
    		while true
    		do
    			read -p "请输入短信内容:" msg
    			sum=$(($sum-$msg_fee))
    			printf "发送 $msg successfully!
    "
    			printf "当前余额:$sum
    "
    			if [ $sum -lt $msg_fee ];then
    				printf "余额不足,剩余 $sum分
    "
    				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}
    "
    		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
    
  • 相关阅读:
    100道MySQL数据库经典面试题解析(收藏版)
    input()函数的进阶用法
    MySQL数据库面试题(2020最新版)
    mysql 1418错误_MySQL 错误1418 的原因分析及解决方法
    使用pymysql循环删除重复数据,并修改自增字段偏移值
    字典get方法和setdesault方法,统计message中各元素的出现频次
    Python中字典get方法的使用技巧
    collections模块
    python的30个编程技巧
    SQL中where与having的区别
  • 原文地址:https://www.cnblogs.com/tongxiaoda/p/7454640.html
Copyright © 2020-2023  润新知