Shell进阶(二)while 循环 中断 select

1.while循环
while CONDITION; do
循环体
done

CONDITION:循环控制条件;进入循环之前,先做一次判断;每一次循环之后会再次做判断;条件为“true”,则执行一次循环;直到条件测试状态为“false”终止循环
因此:CONDTION一般应该有循环控制变量;而此变量的值会在循环体不断地被修正

进入条件:CONDITION为true,不停的循环
退出条件:一旦CONDITION为false,马上退出循环
示例:1.写脚本 whilesum100.sh 从1加到100
sum=0
i=1
while [ ile100];doletsum+=ileti++doneecho i − l e 100 ] ; d o l e t s u m + = i l e t i + + d o n e e c h o sum

2.while99sheet.sh,实现九九乘法表
i=1
while [ ile9];doj=1while[ i − l e 9 ] ; d o j = 1 w h i l e [ j -le i];doechoe i ] ; d o e c h o − e “ j* i= i = [ j j ∗ i]\t\c” #不换行 加空格分隔开
let j++
done
let i++
echo #加个换行
done

3.脚本whiletriangle.sh打印等腰三角形。

算法:
line=总行数
i=当前行
j=当前列
中间的*所在列=line-i
当前行从开头到中间的*个数=i
space数=line-i
当前行* 个数=2*i-1

read -p “Please input a line number: ” line
i=1
while [ “ i"le" i " − l e " line” ];do

打印空格

j=1
while [ jle j − l e [line-i] ];do
echo -n ” ”
let j++
done

打印t *

k=1
while [ kle k − l e [i*2-1] ];do
echo -n “*”
let k++
done
let i++
echo
done

4.写脚本httpdcheck.sh,监测httpd进程是否运行,如果失败则重启httpd服务
while true ;do # true或者:代表永远都是真,不停的循环执行
if killall -0 httpd &> /dev/null ; then #发0信号判定进程是否运行
true #什么也不做
else
service httpd restart
echo “At date +'%F %T' httpd restart” >> ./httpdcheck.log
fi
sleep 10 #每隔10秒执行一次
done

练习:用while实现
1、编写脚本,求100以内所有正奇数之和

2、编写脚本,提示请输入网络地址,如192.168.0.0,判断输入的网段中主机在线状态,并统计在线和离线主机各多少

3、编写脚本,打印九九乘法表

4、编写脚本,利用变量RANDOM生成10个随机数字,输出这个10数字,并显示其中的最大值和最小值
for的另外一种写法for ((exp1|exp2|exp3));do

vim formaxmin.sh
echo -e “random list:\c”
for ((i=0;i<10;i++));do
rand= RANDOMechoe R A N D O M e c h o − e “ rand\c”
if [ ieq0];thenmax= i − e q 0 ] ; t h e n m a x = rand
min= randfiif[ r a n d f i i f [ max -lt rand];thenmax= r a n d ] ; t h e n m a x = rand
elif [ mingt m i n − g t rand ]; then
min= randelsetruefidoneechoechomaxis r a n d e l s e t r u e f i d o n e e c h o e c h o m a x i s max
echo min is $min

5、编写脚本,实现打印国际象棋棋盘

6、后续六个字符串:efbaf275cd、4be9c40b8b、44b2395c46、f8c8873ce0、b902c16c8b、ad865d2f63是通过对随机数变量RANDOM随机执行命令: echo $RANDOM|md5sum|cut -c1-10 后的结果,请破解这些字符串对应的RANDOM值
一点基础知识:
man bash后/RANDOM搜索到,发现RANDOM取值范围是 0 ~ 32767 的整数。
思路:i=RANDOM值,用while作循环。

2.until循环
until CONDITION; do
循环体
done

进入条件: CONDITION 为false
退出条件: CONDITION 为true

示例:1.当有用户登录账户hacker时,就把他踢出去,vim untilkickuser.sh
先来建立一个账号useradd hacker
echo magedu | passwd –stdin hacker
用who | grep -q “^hacker>” 来判断是否登录
echo $? #返回0就是真
方式一:一直运行,登录3秒就踢

!/bin/bash

until false ;do
who | grep -q “^hacker>” && pkill -9 -U hacker
sleep 3
done
方式二:踢掉就关闭脚本

!/bin/bash

until who | grep -q “^hacker>” ;do
sleep 3
done
pkill -9 -U hacker

3.循环控制语句continue
用于循环体中
continue [N]:提前结束第N层的本轮循环,而直接进入下一轮判断;最内层为第1层
continue 2:退出当前层小循环,执行上一层的、外层的大循环
语法:
while CONDTIITON1; do
CMD1

if CONDITION2; then
continue
fi
CMDn

done

示例:1.continuetest.sh
for i {1..10};do
for j in {1..10};do
if [ j -eq 5 ]; then  
cotinue     #结束本小段的循环不执行,但其他循环继续执行  
      fi  
echo j=
j -eq 5 ]; then  cotinue     #结束本小段的循环不执行,但其他循环继续执行        fi  echo j=
j
done
done

4.循环控制语句break

用于循环体中
break [N]:提前结束第N层循环,最内层为第1层
break 2:退出当前层和上一层的所有循环,直接总退出。

while CONDTIITON1; do
CMD1

if CONDITION2; then
break
fi
CMDn

done

5.循环控制shift命令
shift [n]
用于将参量列表 list 左移指定次数,缺省为左移一次。
参量列表 list 一旦被移动,最左端的那个参数就从列表中删除。while 循环遍历位置参量列表时,常用到 shift
./doit.sh a b c d e f g h
./shfit.sh a b c d e f g h

示例:1.doit.sh

!/bin/bash

Name: doit.sh

Purpose: shift through command line arguments

Usage: doit.sh [args]

while [ # -gt 0 ] # or (( # -gt 0 ] # or (( # > 0 ))
do
echo $*
shift
done

2.当前目录下的文件f1–f5,备份到按照日期创建的备份文件夹。
一点基础知识:
[ “ 1"][e" 1 " ] 等 价 于 [ − e " 1” ],在test -e里意思是文件存在,不是空,或者直接写字符串,把-e也可以省掉了

while [ “$1” ]; do
dir=/data/backup/date +%F
[ !-d “$dir” ] && mkdir /data/backup/date +%F

若dir不存在,则创建。!取反 -d目录存在 变量要加引号

[ -f “1" ] && mv 1" ] && mv 1 /data/bakup/date +%F/ && echo $1 is removed
shift
done
echo “done”

6.创建无限循环
while的无限循环:
while true; do
循环体
done

until的无限循环:
until false; do
循环体
done

for的无限循环:
for ((;;));do
echo test
done

练习
1、每隔3秒钟到系统上获取已经登录的用户的信息;如果发现用户hacker登录,则将登录时间和主机记录于日志/var/log/login.log中,并退出脚本

2、随机生成10以内的数字,实现猜字游戏,提示比较大或小,相等则退出
rand= [RANDOMwhilereadpinputadigit110:num;doif[[! [ R A N D O M w h i l e r e a d − p “ i n p u t a d i g i t 1 − 10 : ” n u m ; d o i f [ [ ! num =~ ^[0-9]+ ]];thenechoPleaseinputadigitcontinueelif[ ] ] ; t h e n e c h o “ P l e a s e i n p u t a d i g i t ” c o n t i n u e e l i f [ num -qt rand];thenecho r a n d ] ; t h e n e c h o “ num is greater”
elif [ numlt n u m − l t rand ];then
echo “ numislesserelseecho n u m i s l e s s e r ” e l s e e c h o “ num is bingo”
break
fi
done
3、用文件名做为参数,统计所有参数文件的总行数

4、用二个以上的数字为参数,显示其中的最大值和最小值

5、脚本 diskcheck01.sh,逐行处理df -h 分区利用率大于5%的,显示其分区名和利用率。
参考用例:逐行处理变量读入

df -h | grep /dev/sd | while read disk ;do echo $disk;done|tr -s ” “|cut -d” ” -f1,5
/dev/sda1 16%

warn=5
df -h | grep /dev/sd | while read disk ;do
dn= (echo ( e c h o disk | cut -d” ” -f1)
us= (echo ( e c h o disk | tr -s ” ” “%”| cut -d”%” -f5)
if [ usge u s − g e warn ];then
echo “ dnwillbefull;used d n w i l l b e f u l l ; u s e d warn % ”
fi
done

7.特殊用法
while循环的特殊用法(遍历文件的每一行):
while read line; do
循环体
done < /PATH/FROM/SOMEFILE

依次读取/PATH/FROM/SOMEFILE文件中的每一行,且将行赋值给变量line

练习
1.扫描/etc/passwd文件每一行,如发现GECOS字段为空,则填充用户名和单位电话为62985600,并提示该用户的GECOS信息修改成功
一些基础知识:GECOS字段为第五列 描述
改个人信息:chfn -f 改全名 -p改办公电话
while read line ;do
GECOS=echo "$line" | cut -d: -f5
USER=echo "$line" | cut -d: -f1
[ -z “GECOS" ] && chfn -f GECOS" ] && chfn -f USER -p 62985600 &> /dev/null
done < /etc/passwd

2.lastb命令可以输出最近失败登录的信息,cat /etc/hosts.deny文件可以拒绝下次该IP登录(通过命令: echo sshd:192.168.123.123 >> /etc/hosts.deny)封IP
现在写出一个脚本,denyssh.sh,自动发现并封IP,排除公司内网172.20.0.0网段

先取出IP:lastb | sed -r ‘s/.* (([0-9]{1,3}.){3}[0-9]{1,3}).*/\1/’

-n p 把默认打印关掉,否则最后一行会显示btmp…..

lastb | sed -r ‘s/.* (([0-9]{1,3}.){3}[0-9]{1,3}).*/\1/’ | sort | uniq -c

做个去重复

cat iplist.txt | sed -nr ‘s/ +([0-9]+) +(.*)/\1/p’

做个分组选第一组,取出累计次数

cat iplist.txt | sed -nr ‘s/ +([0-9]+) +(.*)/\2/p’

做个分组选第二组,取出IP地址

下面是脚本的正片:

vim denyssh.sh

iplist.txt
lastb | sed -nr ‘s/.* (([0-9]{1,3}.){3}[0-9]{1,3}).*/\1/p’ | sort | uniq -c > iplist.txt
warn=5
while read line ; do
TIME=echo "$line" | sed -nr 's/([0-9]+) +(.*)/\1/p'
IP=echo "$line" | sed -nr 's/([0-9]+) +(.*)/\2/p'
if [ TIMEge T I M E − g e warn ]; then
[[ $IP =~ ^172.20.0 ]] && continue

把172.20.0网段排除掉(公司内网不能封)

grep -q “ IP"/etc/hosts.deny||echo"sshd: I P " / e t c / h o s t s . d e n y | | e c h o " s s h d : IP” >> /etc/hosts.deny
#-q啥也不做,判断文件里是否有这个IP了已经
fi
done < iplist.txt

3.用ss -nt查看连接,超过3个的,用iptables -A INPUT -s x.x.x.x -j REJECT命令拒该连接,用ACLss.sh 实现。
思路:

iplist.log
ss -nt | sed -nr ‘/EST/s/.* (.):./\1/p’ | sort | uniq -c > iplist.log
warn=3
while read line ;do
TIME=echo "$line" | cut -d" " -f1
IP=echo "$line" | cut -d" " -f2
if [ TIMEge T I M E − g e warn ];then
iptables -A INPUT -s $IP -j REJECT
fi
done < iplist.log

8.特殊用法

双小括号方法,即((…))格式,也可以用于算术运算
双小括号方法也可以使bash Shell实现C语言风格的变量操作
I=10
((I++))
for循环的特殊格式:
for ((控制变量初始化;条件判断表达式;控制变量的修正表达式))
do
循环体
done
控制变量初始化:仅在运行到循环代码段时执行一次
控制变量的修正表达式:每轮循环结束会先进行控制变量修正运算,而后再做条件判断

9.select循环与菜单
select variable in list
do
循环体命令
done

select 循环主要用于创建菜单,按数字顺序排列的菜单项将显示在标准错误上,并显示 PS3 提示符,等待用户输入 #相当于read -p “please input: ” menu
用户输入菜单列表中的某个数字,执行相应的命令
用户输入被保存在内置变量 REPLY 中

示例:1.创建一个点菜单

10.select与case
select 是个无限循环,因此要记住用 break 命令退出循环,或用 exit 命令终止脚本。也可以按 ctrl+c 退出循环
select 经常和 case 联合使用
与 for 循环类似,可以省略 in list,此时使用位置参量


你可能感兴趣的:(linux)