1、while循环
while CONDITION; do
循环体
done
CONDITION:循环控制条件;进入循环之前,先做一次判断;每一次循环之后会再次做判断;条件为“true”,则执行一次循环;直到条件测试状态为“false”终止循环
因此:CONDTION一般应该有循环控制变量;而此变量的值会在循环体不断地被修正
进入条件:CONDITION为true
退出条件:CONDITION为false
举例
#!/bin/bash
sum=0
i=1
while [ $i -le 100 ];do ---先进行判断,如果为真,则执行循环体
let sum+=i ---表示sum=sum+i
let i++ ---表示i=i+1
done
echo sum is $sum
[root@redhat7 app]#i=0;let i++;echo $? ---i++表示先赋值再相加,此时i=0,规定如果let后的值是零,则退出状态码为1
1
[root@redhat7 app]#i=0;let ++i;echo $?---表示先相加再赋值,此时let后的值是1
0
总结:要引起注意,两个返回的值不一样,不小心可能会出错,因为while进行判断时真就进行循环,假就退出循环。
#!/bin/bash
read -p "please input nework(eg:192.168.0.0): " network
netid=`echo $network|cut -d. -f1-3` ---取出网络id位并定义为变量
hostid=1
up=0
down=0
while [ $hostid -le 254 ];do
if ping -c1 -w1 $netid.$hostid &>/dev/null;then ---pingIP地址
echo "the $netid.$hostid is up" ---如果成功则打印ip地址是up
let up++ ---并且让up增加一个
else
echo "the $netid.$hostid is down"
let down++
fi
let hostid++
done
echo up host is $up
echo down host is $down
如何实现死循环
[root@redhat7 app]#while true;do echo xxx;sleep 1;done ---while 后
面的条件如果一直是真,则不会退出循环体,就会一直循环,实现死
循环。
xxx
xxx
[root@redhat7 app]#true ---true的值返回的总是真,可以实现死循环
[root@redhat7 app]#echo $?
0
实现每5秒钟监控一下http这个服务是否正常运行,如果不正常运行,就重启服务,并写进日志
#!/bin/bash
while true;do ---实现死循环
if killall -0 httpd &>/dev/null;then ---监控httpd服务是否正常运行,发0信号就可以监控
echo the htttpd service is normal
else
systemctl restart httpd&>/dev/null
echo "`date '+%F %T'` restart httpd " >>/app/httpd.log ---将什
么时间重启的服务写进日志
fi
sleep 5 ---睡眠5秒后继续执行循环体
done
用while循环实现国际象棋
#!/bin/bash
i=1
while [ $i -le 8 ];do
j=1
while [ $j -le 8 ];do
let flag=i+j
if [ $[flag%2] -eq 0 ];then ---表示进行算术运行,还可以写成
$(flag%2)= $[flag%2],表示取余数的意思,能被2整除就是偶数。
echo -ne "\033[41m \033[0m"
else
echo -ne "\e[43m \e[0m"
fi
let j++
done
echo
let i++
done
总结:国际象棋的特点是八行八列,最外面的while循环打印八行,里面的whlie循环打印八列,其中行号加列号为偶数的是一种背景色,是奇数的为另外一种背景色,根据这个特点可以规定什么时候打印什么背景色。
2、until循环
until CONDITION; do
循环体
done
进入条件:CONDITION 为false
退出条件:CONDITION 为true
总结:until循环和while循环的格式相同,但判断时是假才进入循环体,和while循环正好相反。
3、循环控制语句continue
用于循环体中
continue [N]:提前结束第N层的本轮循环,而直接进入下一轮判断;最内层为第1层
#!/bin/bash
i=1
while [ $i -le 10 ];do
[ $i -eq 5 ]&&continue ---结束本轮循环,而不是退出整个循环
echo i=$i
let i++
done
[root@redhat7 app]#./continue.sh --执行到5的时候,就结束本轮循
环,i也不会加1,此时1一直都是5,页不会打印,因为打印是在
continue后面,就会一直停着,也不会退出。
i=1
i=2
i=3
i=4
#!/bin/bash
i=0
while [ $i -le 10 ];do
let i++
if [ $i -eq 5 ];then
continue
else
echo i=$i
fi
done
执行结果
[root@redhat7 app]#./continue.sh ---当遇到5时就结束本轮循环,不
进行打印5
i=1
i=2
i=3
i=4
i=6
i=7
i=8
i=9
i=10
i=11
4、循环控制语句break
用于循环体中
break [N]:提前结束第N层循环,最内层为第1层
#!/bin/bash
i=0
while [ $i -le 10 ];do
let i++
if [ $i -eq 5 ];then
break
else
echo i=$i
fi
done
执行情况
[root@redhat7 app]#./break.sh
i=1
i=2
i=3
i=4
continue和break的区别:后面不加数字的时候默认都是第1层,也就是最内层,continue是结束第1层的本轮循环,而break是结束第1层循环,比如第一层有10个循环,continue只是结束本层的第几个循环,而break是跳出本层的整个循环。
for i in {1..10};do
for j in {1..10};do
echo -n "$j "
[ $j -eq 5 ]&&continue 2 ---表示当j=5时就跳出第2层也就是最外面层的某一次循环,进行下一次循环,所以不会执行echo换行。
done
echo
done
[root@redhat7 app]#./continue.sh
1 2 3 4 5 1 2 3 4 5 1 2 3 4 5 1 2 3 4 5 1 2 3 4 5 1 2 3 4 5 1 2 3 4 5 1 2 3 4 5 1 2 3 4 5 1 2 3 4 5
2 3 4 5 1 2 3 4 5 [root@redhat7 app]#vim continue.sh
#!/bin/bash
for i in {1..10};do
for j in {1..10};do
echo -n "$j "
[ $j -eq 5 ]&&break 2 ---表示当j=2时跳出整个最外层的循环
done
echo
done
[root@redhat7 app]#./continue.sh
1 2 3 4 5
5、循环控制shift命令
shift [n]
用于将参量列表list 左移指定次数,缺省为左移一次。
参量列表list 一旦被移动,最左端的那个参数就从列表中删除。while 循环遍历位置参量列表时,常用到shift
举例
#!/bin/bash
while [ $# -gt 0 ];do
echo $*
shift
done
[root@redhat7 app]#./shift.sh a b c d e f
a b c d e f
b c d e f
c d e f
d e f
e f
f
#!/bin/bash
while [ $# -gt 0 ];do
id $1 &>/dev/null && continue
useradd $1 &>/dev/null && echo $1 is created
shift ---如果不加shift,始终都是第一个参数,就创建不了其他的
用户了
done
[root@redhat7 app]#./shiftuser.sh lixinru fanbingbing lixiaolu
lixinru is created
fanbingbing is created
lixiaolu is created
6、特殊用法
- while和read配合使用可以依次处理文件或命令的每一行
while循环的特殊用法(遍历文件的每一行):
while read line; do
循环体
done < /PATH/FROM/SOMEFILE
依次读取/PATH/FROM/SOMEFILE文件中的每一行,且将行赋值给变量line
read 等待读取键盘输入,可以用管道,将命令的执行结果逐行的赋值给read定义的变量
举例
扫描/etc/passwd文件每一行,如发现描述信息字段为空,则填充用户
名和单位电话为62985600,并提示该用户的描述信息修改成功。
#!/bin/bash
while read line;do
gecons=`echo $line |cut -d: -f5`
username=`echo $line |cut -d: -f1`
if [ -z $gecons ];then ---表示空为真,空就执行下面的操作,[ -n $gecons ]正好相反,表示非空为真
chfn -f $username -p 62985600 $username &>/dev/null ---chfn
命令可以修改用户的描述信息,其中-f选项是添加描述信息中的用户名,
-p选项是添加单位电话
echo the $username finger is modify
fi
done < /etc/passwd ---逐行的读取这个文件中的每一行赋值给line
也可以用管道
检查分区利用率,发现80%就报警,并且指出设备名
#!/bin/bash
df|grep '/dev/sd'|while read disk;do
diskused=`echo $disk|sed -r 's/^.* ([0-9]{1,2})%.*$/\1/'`
devname=`echo $disk|cut -d ' ' -f1`
[ $diskused -gt 80 ]&& echo "$devname will be full:$diskused%"
done
- 双小括号用法
双小括号方法,即((…))格式,也可以用于算术运算
for循环的特殊格式:
for ((控制变量初始化;条件判断表达式;控制变量的修正表达式))
do
循环体
done
控制变量初始化:仅在运行到循环代码段时执行一次
控制变量的修正表达式:每轮循环结束会先进行控制变量修正运算,而后再做条件判断
举例
#!/bin/bash
for ((i=1,sum=0;i<=100;i++));do ---执行时,控制变量的初始化就刚开始时执行一次,然后进行判断,进入第一次循环,循环结束之后,进行变量的修正,让i增加1,然后再进行判断,进入第二轮循环
let sum+=i
done
echo "sum=$sum"
#!/bin/bash
sum=0
i=1
while ((i<=100));do
let sum+=i
let i++
done
echo "sum=$sum"
7、select循环与菜单
select variable in list
do
循环体命令
done
select 循环主要用于创建菜单,按数字顺序排列的菜单项将显示在标准错误上,并显示PS3 提示符,等待用户输入
用户输入菜单列表中的某个数字,执行相应的命令
用户输入被保存在内置变量REPLY 中
举例
[root@redhat7 script]#select menus in lamian huimian yangtangmian yangroutang;do echo $menus;done
1) lamian
2) huimian
3) yangtangmian
4) yangroutang
#? 1 --输入菜单中的某个数字,执行do之后的命令
lamian
#?
PS3=‘please choose your menu: '可以修改PS3提示符
[root@redhat7 script]#select menus in lamian huimian yangtangmian yangroutang;do echo $menus;done
1) lamian
2) huimian
3) yangtangmian
4) yangroutang
please choose your menu : 1
lamian
please choose your menu : 2
huimian
please choose your menu : 3
yangtangmian
please choose your menu : 4
yangroutang
please choose your menu : 1
lamian
please choose your menu : ---可以发现select循环是个无限循环,不会退出
编写脚本实现点菜功能
#!/bin/bash
PS3='please choose your menu:'
select menu in lamimian huimian yangtangmian yangroutang yangpai;do ----用户输入菜单对应的数字,会执行do循环体内的命令
case $REPLY in ----用户的输入的数字被保存到REPLY变量中
1)
echo "price is \$10"
;;
2)
echo "price is \$15"
;;
3)
echo "price is \$25"
;;
4) echo "price is \$40"
;;
5) echo "price is \$50"
;;
*) echo "get out!"
break
esac
done
总结:select 是个无限循环,因此要记住用break 命令退出循环,或用exit 命令终止脚本。也可以按ctrl+c 退出循环,select 经常和case 联合使用。
PS1命令提示符
PS2多行重定向的命令提示符
8、信号捕捉trap
trap '触发指令' 信号
自定义进程收到系统发出的指定信号后,将执行触发指令,而不会执行原操作
trap ' ' 信号:忽略信号的操作
trap '-' 信号:恢复原信号的操作
trap -p:列出自定义信号操作
trap -l:查看都有哪些信号
举例
[root@redhat7 script]#trap -l ---查看信号,2信号表示ctrl+c
1) SIGHUP 2) SIGINT 3) SIGQUIT 4) SIGILL 5) SIGTRAP
6) SIGABRT 7) SIGBUS 8) SIGFPE 9) SIGKILL 10) SIGUSR1
11) SIGSEGV 12) SIGUSR2 13) SIGPIPE 14) SIGALRM 15) SIGTERM
16) SIGSTKFLT 17) SIGCHLD 18) SIGCONT 19) SIGSTOP 20) SIGTSTP
21) SIGTTIN 22) SIGTTOU 23) SIGURG 24) SIGXCPU 25) SIGXFSZ
26) SIGVTALRM 27) SIGPROF 28) SIGWINCH 29) SIGIO 30) SIGPWR
31) SIGSYS 34) SIGRTMIN 35) SIGRTMIN+1 36) SIGRTMIN+2 37) SIGRTMIN+3
38) SIGRTMIN+4 39) SIGRTMIN+5 40) SIGRTMIN+6 41) SIGRTMIN+7 42) SIGRTMIN+8
43) SIGRTMIN+9 44) SIGRTMIN+10 45) SIGRTMIN+11 46) SIGRTMIN+12 47) SIGRTMIN+13
48) SIGRTMIN+14 49) SIGRTMIN+15 50) SIGRTMAX-14 51) SIGRTMAX-13 52) SIGRTMAX-12
53) SIGRTMAX-11 54) SIGRTMAX-10 55) SIGRTMAX-9 56) SIGRTMAX-8 57) SIGRTMAX-7
58) SIGRTMAX-6 59) SIGRTMAX-5 60) SIGRTMAX-4 61) SIGRTMAX-3 62) SIGRTMAX-2
63) SIGRTMAX-1 64) SIGRTMAX
#!/bin/bash
trap 'echo "you are a baby"' int ---注意int前面一定要有空格,这是一个坑,没有空格脚本执行有错误,并且单引号里面要放命令,意思是执行这个信号后会执行什么命令
trap -p ---列出自定义的信号
for ((i=1;i<10;i++));do
echo $i
sleep 0.5
done
[root@redhat7 script]#./trap.sh
trap --'echo "you are a baby"' SIGINT ---显示出自定义的信号
1
2
^Cpress ctrl+c ---原来按ctrl+c时就终止这个脚本,此时按ctrl+c不起
作用,不会终止脚本,而是在屏幕上打印一句话。
3
4
^Cyou are a baby
5
6
^Cyou are a baby
7
8
^Cyou are a baby
9
#!/bin/bash
trap '' int ---双引号中间什么也没有表示忽略信号的操作,当你按ctrl+c时,不会停止脚本的运行
for ((i=1;i<10;i++));do
echo $i
sleep 1
done
#!/bin/bash
trap '-' int ---双引号中间放个-表示恢复信号的操作,此时再按ctrl+c就可以停止脚本了
for ((i=1;i<10;i++));do
echo $i
sleep 1
done
#!/bin/bash
trap 'echo nozuonodi' term ---换一个信号,15信号是杀死进程,信号的名字是sigterm,大小写都可以,也可以简写为term
trap -p
for ((i=1;i<100;i++));do
echo $i
sleep 1
done
killall trap.sh 当执行这个命令时,原操作是会杀死进程,现在不可
以了,而是在屏幕上打印一句话nozuonodi