循环
循环执行
将某代码段重复运行多次
重复运行多少次循环次数事先已知
循环次数事先未知有进入条件和退出条件
for, while, until
for循环
- 用法:
for NAME [in WORDANDS; S ...]; do COMMdone
for 变量名 in 列表;do 循环体 done
- 执行机制:
依次将列表中的元素赋值给“变量名”; 每次赋值后即执 行一次循环体; 直到列表中的元素耗尽,循环结束
-
列表生成方式:
直接给出列表
整数列表:{start..end}
$(seq [start [step]] end)返回列表的命令
$(COMMAND)
使用glob,如:.sh
变量引用; $@, $ - 练习
1、判断/var/目录下所有文件的类型 --->在做一次
#!/bin/bash
for i in /var/* ;do
if [ -b $i ];then
echo "$i是块设备"
elif [ -c $i ] ;then
echo "$i是字符设备"
elif [ -f $i ];then
echo "$i是普通文件"
elif [ -h $i ];then
echo "$i是符号链接文件"
elif [ -p $i ];then
echo "$i是管道文件"
elif [ -S $i ];then
echo "$i是套接字文件"
elif [ -d $i ];then
echo "$i是目录文件"
else
echo "文件或目录不存在"
fi
done
2、添加10个用户user1-user10,密码为8位随机字符,并且把生成的用户名及密码保存到/app/newuser.txt文件中
#!/bin/bash
for i in `seq 1 5` ; do
username=user$i
useradd $username
password=`openssl rand -base64 10 | head -c 8`
echo $password | passwd --stdin $username &> /dev/null
echo $username $password >> /app/password.txt
done
echo "ok"
3、/etc/rc.d/rc3.d目录下分别有多个以K开头和以S开头的文件 ;分别读取每个文件,以K开头的输出为文件加stop,以S开头的输 出为文件名加start,如K34filename stop S66filename start --->在做一次
#!/bin/bash
for i in /etc/rc.d/rc3.d/[SK]* ;do
if [ $(basename $i | cut -c1) == "K" ] ;then
echo "`basename $i` stop"
else
echo "`basename $i` start"
fi
done
4、编写脚本,提示输入正整数n的值,计算1+2+...+n的总和
#!/bin/bash
read -p "Please input a positive integer: " num
for i in `seq 1 $num` ; do
let sum+=$i
done
echo $sum
5、计算100以内所有能被3整除的整数之和
#!/bin/bash
for i in `seq 0 3 100` ; do
let sum+=$i
done
echo $sum ------>1683
6、计算100以内所有不能被3整除的整数之和
for i in `seq 1 100` ; do
if [ "$[i%3]" -ne 0 ] ; then
let sum+=$i
fi
done
echo $sum ------>3376
7、编写脚本,提示请输入网络地址,如192.168.0.0,判断输入的网段中主机在线状态
#!/bin/bash
> /app/ip.log
read -p "Please input the network(eg:172.18.1.0): " network
[[ "$network" =~ ^(([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])\.){3}([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])$ ]] || { echo "Please input a legal IP " ; exit 250; } ----->**一定要注意250后的分号,机器容易忽略的位置**
net=`echo $network | cut -d. -f 1-3`
for i in {1..254} ; do
{
if ping -c 1 -w 1 $net.$i &> /dev/null ; then
echo $net.$i is up | tee -a /app/ip.log
else
echo $net.$i is down
fi
}&
done
wait
8、打印九九乘法表
#!/bin/bash
for i in `seq 1 9` ; do
for j in `seq $i` ; do
echo -e "${j}x${i}=$[i*j]\t\c"
done
echo
done
9、在/testdir目录下创建10个html文件,文件名格式为数字N(从1到10)加随机8个字母,如:1AbCdeFgH.html
#!/bin/bash
for i in {1..10} ; do
touch /testdir/"$i"`openssl rand -base64 100 | tr -dc '[:alpha:]' | head -c 8`.html
done
10、打印等腰三角形
#!/bin/bash
read -p "Please enter a number: " x
for i in `seq $x` ; do
let space=$x-$i
let xing=2*$i-1
for j in `seq $space` ; do
echo -e " \c"
done
for k in `seq $xing` ; do
echo -e "*\c"
done
echo
done
until循环
- 用法
until CONDITION; do 循环体 done 进入条件: CONDITION 为false 退出条件: CONDITION 为true
循环控制语句continue
- continue用于循环体中
- continue [N]:提前结束第N层的本轮循环,而直接进入下一轮判断;最内层为第1层
- 用法:
while CONDTIITON1; do CMD1 ... if CONDITION2; then continue fi CMDn ... done
循环控制语句break
- break用于循环体中
- break [N]:提前结束第N层循环,最内层为第1层
- 用法:
while CONDTIITON1; do CMD1 ... if CONDITION2; then break fi CMDn ... done
循环控制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
示例:doit.sh
#!/bin/bash
# Name: doit.sh
# Purpose: shift through command line arguments # Usage: doit.sh [args]
while [ $# -gt 0 ] # or (( $# > 0 )) ; do
echo $*
shift
done
示例:shift.sh
#!/bin/bash
#step through all the positional parameters
until [ -z "$1" ] ; do
echo "$1"
shift
done
echo
for 特殊用法
- 双小括号方法,即((...))格式,也可以用于算术运算
- 双小括号方法也可以使bash Shell实现C语言风格的变量操作
I=10
((I++)) - 控制变量初始化:仅在运行到循环代码段时执行一次
- 控制变量的修正表达式:每轮循环结束会先进行控制变量修正运算,而后再做条件判断
-
用法
for ((控制变量初始化;条件判断表达式;控制变量的修正表达式)) do 循环体 done for ((: for (( exp1; exp2; exp3 )); do COMMANDS; done Arithmetic for loop. Equivalent to (( EXP1 )) while (( EXP2 )); do COMMANDS (( EXP3 )) done
示例:
1、求1-100的和
写法1
#!/bin/bash
sum=o
for ((i=1;i<=100;i++)) ; do
let sum+=i
done
echo sum=$sum
写法2
for ((sum=0,i=1;i<=100;i++)) ; do
let sum+=i
done
echo sum=$sum
2、求1-100中 3 的整数倍的和
用for写法
for ((sum=0,i=0;i<=100;i+=3)) ; do
let sum+=i
done
echo sum=$sum
用while写法
sum=0
i=0
while [ "$i" -le 100] ; do
let sum+=i
let i+=3
done
echo sum=$sum
3、打印9x9表
for ((i=1;i<=9;i++)) ; do
for ((j=1;j<=i;j++)) ; do
echo -ne "${j}x${i}=$[$i*$j]\t" ;
done
echo
done
- 练习
1、每隔3秒钟到系统上获取已经登录的用户的信息;如果发 现用户hacker登录,则将登录时间和主机记录于日志 /var/log/login.log中,并退出脚本 --->在做一次
#!/bin/bash
username=cent
{
while true ;do
if who | egrep "^\b$username\b" &> /dev/null ;then
who | egrep "^\b$username\b" >> /var/log/login.log
echo "$username 已登录"
echo "fuck ,go out my system" | write $username
else
echo "$username 已下线"
fi
sleep 3
done
}
2、随机生成10以内的数字,实现猜字游戏,提示比较大或小 ,相等则退出
suiji=`echo $[$RANDOM%10+1]`
read -p "Please input a number in 1-10: " num
until [[ "$num" -eq "$suiji" ]] ; do
if [[ "$num" -lt "$suiji" ]] ; then
read -p "less than random: " num
else
read -p "much than random: " num
fi
done
echo -e "\e[32mCongratulations! The random is $suiji!\e[37m"
3、用文件名做为参数,统计所有参数文件的总行数
4、用二个以上的数字为参数,显示其中的最大值和最小值
while 循环
-
用法
while CONDITION; do 循环体 done
CONDITION:循环控制条件;进入循环之前,先做一次判 断;每一次循环之后会再次做判断;条件为“true”,则执行 一次循环;直到条件测试状态为“false”终止循环
因此:CONDTION一般应该有循环控制变量;而此变量的值 会在循环体不断地被修正
进入条件:CONDITION为true
退出条件:CONDITION为false - 创建无线循环
while true; do 循环体 done
-
while循环的特殊用法
遍历文件的每一行
while read line; do 循环体 done < /PATH/FROM/SOMEFILE 依次读取/PATH/FROM/SOMEFILE文件中的每一行, 且将行赋值给变量line 示例: 扫描/etc/passwd文件每一行,如发现GECOS字段为空,则填 充用户名和单位电话为62985600,并提示该用户的GECOS信 息修改成功。
- 练习
1、编写脚本,求100以内所有正奇数之和
#!/bin/bash
i=1
while [ "$i" -le 100 ] ; do
if [ $[$i%2] -ne 0 ] ; then
let sum+=$i
fi
let i++
done
echo $sum
2、编写脚本,提示请输入网络地址,如192.168.0.0,判断输入的网段中主机在线状态,并统计在线和离线主机各多少
#!/bin/bash
read -p "Please input the network(eg:172.18.0.1): " network
[[ "$network" =~ ^(([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-9])\.){3}([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-9])$ ]] || { echo "Please input a legal IP " ; exit 250 ; }
net=`echo $network | cut -d. -f 1-3`
i=1
up=0
down=0
while [ "$i" -le 254 ] ; do
ping -c 1 -w 1 $net.$i &> /dev/null && { echo $net.$i is up ; let ++up ; } || { echo $net.$i is down ; let down++ ; }
let i++
done
wait
echo i=$i
echo up host is $up
echo down host is $down
3、编写脚本,打印九九乘法表
#!/bin/bash
i=1
j=1
while [ $i -le 9 ] ;do
while [ $j -le $i ] ;do
echo -ne "${j}x${i}=$[i*j]\t"
let j+=1
done
let i+=1
j=1
echo
done
4、编写脚本,利用变量RANDOM生成10个随机数字,输出 这个10数字,并显示其中的最大值和最小值
#!/bin/bash
let i=0,min=max=$RANDOM
echo "$min "
while [ $i -lt 9 ];do
ran=$RANDOM
echo "$ran "
if [ $ran -ge $max ];then
let max=ran
fi
if [ $ran -le $min ];then
let min=ran
fi
let i+=1
done
echo "最大值是 $max ,最小值是 $min"
5、编写脚本,实现打印国际象棋棋盘
#!/bin/bash
let x=y=1
h=8
while [ $x -le $h ];do
while [ $y -le $h ];do
if [ $[(x+y)%2] -eq 0 ] ;then
echo -en "\033[47m \033[0m"
else
echo -en "\033[40m \033[0m"
fi
let y+=1
done
echo
let x+=1,y=1
done
6、后续六个字符串:efbaf275cd、4be9c40b8b、 44b2395c46、f8c8873ce0、b902c16c8b、ad865d2f63 是通过对随机数变量RANDOM随机执行命令:echo $RANDOM|md5sum|cut –c1-10 后的结果,请破解这些字符串对应的RANDOM值
#!/bin/bash
key_num_array=(efbaf275cd 4be9c40b8b 44b2395c46 f8c8873ce0 b902c16c8b ad865d2f63)
for true_num in `seq 0 65535`;do
key_num=`echo $true_num | md5sum | cut -c 1-10`
for num in ${key_num_array[*]}; do
if [ "$key_num" == "$num" ];then
echo "$num --> $true_num"
fi
done
done
7 、检测httpd服务是否处于开启状态,如果处于关闭状态,即刻开启服务
#!/bin/bash
sleeptime=30
while true ; do
if killall -0 httpd &> /dev/null ; then
true
else
service httpd restart
time=`date +"%F %T"`
echo "At $time httpd is restart" >> /app/httpd.log
fi
sleep $sleeptime
done
8、检测磁盘利用率,如果大于80,就发出警报,每5分钟检测一次
第一种方法:
while true ; do
df -h | grep "/dev/sd" | while read disk ; do
per=`echo $disk | sed -r 's/.* (.*)%.*/\1/'`
part=`echo $disk | cut -d" " -f1`
[ "$per" -gt 80 ] && echo "$part will be full,over 80%"
done
sleep 300
done
第二种方法-做成计划任务调用脚本,脚本内容如下
used=10
df -h | grep "/dev/sd" | while read disk ; do
per=`echo $disk | sed -r 's/.* (.*)%.*/\1/'`
part=`echo $disk | cut -d" " -f1`
[ "$per" -gt "$used" ] && echo "$part will be full,over ${used}%"
done
select循环与菜单
- select 循环主要用于创建菜单,按数字顺序排列的 菜单项将显示在标准错误上,并显示 PS3 提示符,等待用户输入
- 用户输入菜单列表中的某个数字,执行相应的命令
- 用户输入被保存在内置变量 REPLY 中
- 用法
select variable in list do 循环体命令 done
- select 是个无限循环,因此要记住用 break 命令退 出循环,或用 exit 命令终止脚本。也可以按 ctrl+c 退出循环
- select 经常和 case 联合使用
- 与 for 循环类似,可以省略 in list,此时使用位置 参量
示例:
1、用while完成的菜单
#!/bin/bash
cat <<EOF
1 yxrs
2 gbjd
3 lzjd
4 lamian
5 huimian
6 yangroutang
7 quit
EOF
while read -p "Please choose the menu number: " menu ; do
case $menu in
1|2)
echo The price is 20
;;
3|6)
echo The price is 25
;;
4|5)
echo The price is 15
;;
7)
break
;;
*)
echo "Please choose again"
;;
esac
done
2、用select 完成
PS3="Please choose the menu number: "
select menu in gbjd yxrs lamian huimian baoyu quit ; do
case $menu in
gbjd|yxrs)
echo The price is 25
;;
lamian|huimian)
echo The price is 15
;;
baoyu)
echo The price is 100
;;
quit)
break
;;
*)
echo "Try choose again"
;;
esac
done
3、select 与 $REPLY 配合
PS3="Please choose the menu number: "
select menu in gbjd yxrs lamian huimian baoyu quit ; do
case $REPLY in
1|2)
echo The price is 25
;;
3|4)
echo The price is 15
;;
5)
echo The price is 100
;;
6)
break
;;
*)
echo "Try choose again"
;;
esac
done
trap 信号捕捉
- trap '触发指令' 信号 自定义进程收到系统发出的指定信号后,将执行触发指令,而不会执行原操作
-
用法
trap '' 信号
忽略信号的操作
trap '-' 信号
恢复原信号的操作
trap -p
列出自定义信号操作
- trap示例
#!/bin/bash
trap 'echo “signal:SIGINT"' int
trap -p
for((i=0;i<=10;i++))
do
sleep 1
echo $i
done
trap '' int
trap -p
for((i=11;i<=20;i++))
do
sleep 1
echo $i
done
trap '-' int
trap -p
for((i=21;i<=30;i++))
do
sleep 1
echo $i
done
#!/bin/bash
trap `echo Do not break` INT
fo i in {1..10} ; do
echo $i
sleep 0.5
done
转载于:https://blog.51cto.com/exia00linux/2058422