for 循环语句
循环固定次数
语法结构:
1、列表for循环:用于将一组命令执行已知的次数,下面给出了for循环语句的基本格式:
for variable in {list}
do
command
command
…
done
或者
for variable in a b c
do
command
command
done
2、不带列表for循环:执行时由用户指定参数和参数的个数,下面给出了不带列表的for循环的基本格式:
for variable
do
command
command
…
done
3、类C风格的for循环:一般用于循环次数已知的情况,下面给出了类C风格的for循环的语法格式:
for(( expr1; expr2; expr3 ))
do
command
command
…
done
表达式expr1:循环变量赋初值的语句
表达式expr2:决定是否进行循环的表达式,当判断expr2退出状态为0执行do和done之间的循环体,当退出状态为非0时将退出for循环执行done后的命令
表达式expr3:用于改变循环变量的语句
循环示例:
1119 for ((i=1;i<=5;i++));do echo $i;done
1120 for ((i=1;i<=5;++i));do echo $i;done
1121 for i in {1..50};do echo $i;done
1122 for i in {1..10};do echo $i;done
1123 for i in 1 2 3 4 5 6 7 8 9 10;do echo $i;done
1124 for i in `seq 10`;do echo $i;done
1125 for i in $(seq 10);do echo $i;done
1127 for i in {1..10..2};do echo $i;done
1128 for i in {0..10..2};do echo $i;done
1129 for i in `seq 1 2 10`;do echo $i;done
1130 for i in `seq 0 2 10`;do echo $i;done
1131 for ((i=1;i<=10;i+=2));do echo $i;done
demo1:
计算1到100的奇数之和,方法不止一种
方法1:
#!/bin/bash
sum=0
for i in {1..100..2}
do
echo sum=$[$sum+$i]
done
echo "1到100的奇数之和为:$sum"
方法2:
sum=0
for((i=1;i<=100;i+=2))
do
let sum=$sum+$i
done
echo "1到100的奇数之和为:$sum"
方法3:
#!/bin/bash
sum=0
for i in `seq 100`
do
[ $[$i%2] -ne 0 ] && sum=$[$sum+$i]
done
echo "1到100的奇数之和为:$sum"
方法4:
#!/bin/bash
sum=0
for i in `seq 100`
do
[ $[$i%2] -eq 0 ] && continue || sum=$[$sum+$i]
done
echo "1到100的奇数之和为:$sum"
#!/bin/bash
sum=0
for i in `seq 100`
do
if [ $[$i%2] -eq 0 ];then
continue
else
sum=$[$sum+$i]
fi
done
echo "1到100的奇数之和为:$sum"
循环控制:
continue:继续。表示循环体内下面的代码不执行,重新开始下一次循环
break:打断。马上停止执行本次循环,执行循环体后面的代码
exit:表示直接跳出程序
demo2:
输入一个正整数,判断是否为质数(素数)
质数:只能被1和它本身整除的数叫质数。
2 3 5 7 11 13 17 19 23 29 31 37 41 43 47 53 59 61 67 71 73 79 83 89 97
思路:
1、如果能被其他数整除就不是质数——>$num%$i 是否等于0
2、如果输入的数是1或者2取模根据上面判断又不符合,所以先排除1和2
3、测试序列从3开始,输入的数是4——>得出结果$num不能和$i相等,并且$num不能小于$i
#!/bin/bash
read -p "输入一个正整数(大于等于1):" num
if [ $num -eq 2 ];then
echo "$num是质数"
exit
elif [ $num -eq 1 ];then
echo "$num不是质数"
exit
fi
for i in `seq 2 $[$num-1]` #如果结束序列等于或者大于num变量本身,则变量i总有一次和num相等,所以不能大于等于
do
if [ $[$num%$i] -eq 0 ];then
echo "$num不是质数"
exit 2
fi
done
echo "$num是质数"
demo3:
批量加5个新用户,以u1到u5命名,并统一加一个新组,组名为class,统一改密码为123
#!/bin/bash
grep ^class$ /etc/group &>/dev/null
test $? -ne 0 && groupadd class
for i in {1..5}
do
useradd u$i -G class
echo 123|passwd --stdin u$i &>/dev/null
done
#!/bin/bash
groupadd class &>/dev/null
for ((i=1;i<=5;i++))
do
useradd u$i -G class
echo 123|passwd --stdin u$i &>/dev/null
done
思考:如果事先需要判断class组是否存在,怎么办?
cut -d: -f1 /etc/group |grep -w class
-w:精确匹配
课堂练习:
1、再次批量新建5个用户stu1~stu5,要求这几个用户的家目录都在/rhome.提示:需要判断该目录是否存在
#!/bin/bash
dir=/rhome
test ! -d $dir && mkdir $dir
或者
[ ! -d $dir ] && mkdir $dir
或者
if [ ! -d $dir ];then
mkdir $dir
fi
for i in {1..5}
do
useradd -d $dir/stu$i stu$i
echo 123|passwd --stdin stu$i
done
如何再去判断用户是否存在?如果存在就不创建,如果不存在就创建它
2、写一个脚本,局域网内,把能ping通的IP和不能ping通的IP分类,并保存到两个文本文件里(如果例举整个网段的254个IP花的时间比较长,可以只分类10个ip192.168.1.10~20) 这只是一个局域网内机器检查通讯的一个思路。
需求:172.16.13.1~172.16.13.254
#!/bin/bash
for i in {1..254}
do
echo 172.16.13.$i >> /shell/shell02/ip.txt
done
for i in `cat /shell/shell02/ip.txt`
do
ping -c1 $i &>/dev/null
[ $? -eq 0 ] && echo $i >> /shell/shell02/ip_ok.txt || echo $i >> /shell/shell02/ip_down.txt
done
#!/bin/bash
ip=172.16.13.
for i in {1..254}
do
ping -c1 $ip$i &>/dev/null
[ $? -eq 0 ] && echo $i >> /shell/shell02/ip_ok.txt || echo $i >> /shell/shell02/ip_down.txt
done
until循环
条件为真就退出循环;条件为假就死循环
语法结构:
until expression
do
command
command
…
done
until循环中expression的退出状态不为0(表达式为假)将循环体一直执行下去,直到退出状态为0(表达式为真)
demo1:用until实现打印1到5
demo2:用until改写批量创建用户
1198 until false;do echo hello;done
1199 i=1;until [ $i -gt 5 ];do echo $i;let i++;done
# cat until1.sh
#!/bin/bash
i=1
until [ $i -gt 5 ]
do
echo $i
let i=$i+1
done
1210 for ((i=1;i<=10;i+=2));do echo $i;done
1211 i=1;until (( $i > 10 ));do echo $i;let i+=2;done
1212 i=1;until [ $i -gt 10 ];do echo $i;let i+=2;done
1214 sum=0;for ((i=1;i<=10;i+=2));do sum=$[$sum+$i];echo "sum=$sum";done
1215 sum=0;for ((i=1;i<=10;i+=2));do sum=$[$sum+$i];done;echo "sum=$sum"
1216 sum=0;i=1;until (( $i > 10 ));do sum=$[$sum+$i];let i+=2;done;echo "sum=$sum"
1217 sum=0;i=1;until [ $i -gt 10 ];do sum=$[$sum+$i];let i+=2;done;echo "sum=$sum"
#!/bin/bash
i=1
until [ $i -gt 5 ]
do
useradd uu$i
echo 123|passwd --stdin uu$i &>/dev/null
let i++
done
while循环
满足条件(真)就进入死循环;条件为假就退出循环
语法结构:
while expression 只要条件满足就一直循环
do
command
command
done
计算1-50的偶数之和
1230 sum=0;i=2;while [ $i -le 50 ];do sum=$[$sum+$i];let i+=2;done
1231 sum=0;i=2;while [ $i -le 50 ];do sum=$[$sum+$i];let i+=2;done;echo "sum=$sum"
1232 sum=0;i=1;while [ $i -le 50 ];do sum=$[$sum+$i];let i+=2;done;echo "sum=$sum"
demo1:打印1-5数字
demo2:
写一个30秒同步一次时间同步服务器172.16.13.250的脚本,如果同步失败,则进行邮件报警,每次失败都报警;同步成功,也进行邮件通知,但是成功100次才通知一次。
rdate -s 172.16.13.250
ntpdate 172.16.13.250
#!/bin/bash
ip=172.16.13.250
count=0
while true
do
rdate -s $ip &>/dev/null
[ $? -ne 0 ] && echo "系统时间同步失败,请注意" |mail -s "系统时间同步检查" root ||let count++
[ $count -eq 100 ] && echo "系统时间同步成功100次" |mail -s "系统时间同步检查" root && count=0
sleep 30
done
#!/bin/bash
count=0
while true
do
ntpdate 192.168.1.10 &> /dev/null
if [ $? -ne 0 ];then
echo "ntpdate failed" |mail -s "time sync problem" mail01
else
let count++ 或者let count=$count++
if [ $count -eq 100 ];then
echo "ntpdate successd" |mail -s "time sync ok" mail01
count=0
fi
或者
[ $count -eq 100 ] && echo "ntpdate successd" |mail -s "time sysnc ok" root && count=0
或者
[ $[$count%100] -eq 0 ] && echo "ntpdate successd" |mail -s "time sysnc ok" root
fi
sleep 30
done
注意:因为是一个死循环,所以放到后台执行。
总结:
用至少三种方法打印1~5和5~1
打印1~5:
for i in {1..5};do echo $i;done
for i in `seq 5`;do echo $i;done
for ((i=1;i<=5;i++));do echo $i;done
while和until
打印5~1:
# for i in {5..1};do echo $i;done
# for i in `seq 5 -1 1`;do echo $i;done
# for ((i=5;i>=1;i--));do echo $i;done
while和until
1262 for ((i=1;i<=5;i++));do echo $i;done
1263 for ((i=5;i>=1;i--));do echo $i;donw
1264 for ((i=5;i>=1;i--));do echo $i;done
1265 i=1;until [ $i -gt 5 ];do echo $i;let i++;done
1266 i=5;until (( $i < 1 ));do echo $i;let i--;done
1267 i=1;until (( $i > 5 ));do echo $[6-$i];let i++;done
1268 i=1;while [ $i -le 5 ];do echo $i;let i++;done
1269 i=1;while (( $i <= 5 ));do echo $((6-$i));let i++;done
随机数:
bash默认有一个$RANDOM的变量
默认是0~32767。使用set |grep RANDOM
查看上一次产生的随机数
echo $RANDOM
产生0~1之间的随机数
echo $[$RANDOM%2]
产生0~2之间的随机数
echo $[$RANDOM%3]
产生0~3之间的随机数
echo $[$RANDOM%4]
。。。。
产生0~9内的随机数
echo $[$RANDOM%10]
产生0~100内的随机数
echo $[$RANDOM%101]
产生50-100之内的随机数
echo $[$RANDOM%51+50]
产生三位数的随机数
echo $[$RANDOM%900+100]
demo1:
写一个脚本,产生一个phonenum.txt文件,随机产生以139开头的手机号1000个,每个一行。
方法一:
for i in `seq 1000`
do
n1=$[$RANDOM%10]
n2=$[$RANDOM%10]
n3=$[$RANDOM%10]
n4=$[$RANDOM%10]
n5=$[$RANDOM%10]
n6=$[$RANDOM%10]
n7=$[$RANDOM%10]
n8=$[$RANDOM%10]
echo "139$n1$n2$n3$n4$n5$n6$n7$n8" >> phonenum.txt
done
方法二:
count=0
while true
do
n1=$[$RANDOM%10]
n2=$[$RANDOM%10]
n3=$[$RANDOM%10]
n4=$[$RANDOM%10]
n5=$[$RANDOM%10]
n6=$[$RANDOM%10]
n7=$[$RANDOM%10]
n8=$[$RANDOM%10]
echo "139$n1$n2$n3$n4$n5$n6$n7$n8" >> phonenum.txt && let count++
if [ $count -eq 1000 ];then
break
fi
done
demo2:再写一个脚本,在上面的1000个手机号里抽奖5个幸运观众,显示出这5个幸运观众。但只显示头3个数和尾号的4个数,中间的都用*代替
#第一种抽法,每个人不限次数
#!/bin/bash
file=/shell/shell02/phonenum.txt
for i in {1..5}
do
line=`wc -l $file |cut -d' ' -f1`
luck=$[$RANDOM%$[$line+1]]
lucknum=`head -$luck $file|tail -1`
echo "幸运观众是:139****${lucknum:7:4}"
done
#第二种抽法,每个人就只有一次机会
#!/bin/bash
file=/shell/shell02/phonenum.txt
for i in {1..5}
do
line=`wc -l $file |cut -d' ' -f1`
luck=$[$RANDOM%$[$line+1]]
lucknum=`head -$luck $file|tail -1`
sed -i "/$lucknum/d" $file
echo "幸运观众是:139****${lucknum:7:4}"
done
嵌套循环
一个循环体内又包含另一个完整的循环结构,称为循环的嵌套。在外部循环的每次执行过程中都会触发内部循环,直至内部完成一次循环,才接着执行下一次的外部循环。for循环、while循环和until循环可以相互嵌套。
demo1:打印如下图案
1
12
123
1234
12345
#!/bin/bash
for ((y=1;y<=5;y++))
do
for ((x=1;x<=$y;x++))
do
echo -n $x
done
echo
done
#!/bin/bash
for ((y=1;y<=5;y++))
do
x=1
while [ $x -le $y ]
do
echo -n $x
let x++
done
echo
done
#!/bin/bash
y=1
until (( $y > 5 ))
do
x=1
while (( $x <=$y ))
do
echo -n $x
let x++
done
echo
let y++
done
demo2:打印如下图案
5
54
543
5432
54321
for ((y=5;y>=1;y--))
do
x=5
until (( $x < $y ))
do
echo -n $x
let x--
done
echo
done
课堂练习:打印九九乘法表(三种方法)
1*1=1
1*2=2 2*2=4
1*3=3 2*3=6 3*3=9
1*4=4 2*4=8 3*4=12 4*4=16
1*5=5 2*5=10 3*5=15 4*5=20 5*5=25
1*6=6 2*6=12 3*6=18 4*6=24 5*6=30 6*6=36
1*7=7 2*7=14 3*7=21 4*7=28 5*7=35 6*7=42 7*7=49
1*8=8 2*8=16 3*8=24 4*8=32 5*8=40 6*8=48 7*8=56 8*8=64
1*9=9 2*9=18 3*9=27 4*9=36 5*9=45 6*9=54 7*9=63 8*9=72 9*9=81
方法一(for循环):
方法二:while循环
方法三:until循环
练习
x
xxx
xxxxx
xxxxxxx
xxxxxxxxx
#!/bin/sh
i=1
while [ $i -le 5 ] ; do
j=1
while [ $j -le $((5-$i)) ] ; do
echo -n ' '
j=$(($j+1))
done
j=1
while [ $j -le $((2*$i-1)) ] ; do
echo -n x
j=$(($j+1))
done
echo
i=$(($i+1))
done
exit 0
作业:
1、将/etc/passwd里的用户名分类,分为管理员用户,系统用户,普通用户。
#!/bin/bash
for i in `cut -d: -f1,3 /etc/passwd`
do
uid=`echo $i|cut -d: -f2`
name=`echo $i|cut -d: -f1`
[ $uid -eq 0 ] && echo $name >> /tmp/管理员
[ $uid -gt 0 -a $uid -lt 500 -o $uid -eq 65534 ] && echo $name >> /tmp/系统用户
[ $uid -ge 500 -a $uid -ne 65534 ] && echo $name >>/tmp/普通用户
done
参考:
作业1:
1、将/etc/passwd里的用户名分类,分为管理员用户,系统用户,普通用户。
答:
写法1
#!bin/bash
for i in `cat /etc/passwd|cut -d: -f1`
do
[ $(id $i -u) -eq 0 ] && admin=$i
[ $(id $i -u) -gt 0 -a $(id $i -u) -lt 500 ] && sys=$sys$i" "
[ $(id $i -u) -ge 500 -a $(id $i -u) -lt 65535 ] && custom=$custom$i" "
done
echo -e "管理员用户:\n $admin \n系统用户:\n ${sys}\n普通用户:\n ${custom}"
--------------------------------------------------------
写法2
#!bin/bash
for i in `cat /etc/passwd|cut -d: -f1,3`
do
[ ${i#*:} -eq 0 ] && admin=${i%:*}
[ ${i#*:} -gt 0 -a ${i#*:} -lt 500 ] && sys=$sys${i%:*}" "
[ ${i#*:} -ge 500 -a ${i#*:} -lt 65535 ] && custom=$custom${i%:*}" "
done
echo -e "管理员用户:\n $admin \n系统用户:\n ${sys}\n普通用户:\n ${custom}"
--------------------------------------------------------
写法3
#!bin/bash
for i in `cat /etc/passwd|cut -d: -f1,3`
do
x=`echo $i|cut -d: -f2`
y=`echo $i|cut -d: -f1`
[ $x -eq 0 ] && admin=$y
[ $x -gt 0 -a $x -lt 500 ] && sys=$sys$y" "
[ $x -ge 500 -a $x -lt 65535 ] && custom=$custom$y" "
done
echo -e "管理员用户:\n $admin \n系统用户:\n ${sys}\n普通用户:\n ${custom}"
------------------------------------------------------
2、写一个倒计时脚本,要求显示离2017年10月1日(国庆节)的凌晨0点,还有多少天,多少时,多少分,多少秒。
#!/bin/bash
guoqing=`date +%s -d '2017-10-01 00:00:00'`
while true
do
now=`date +%s`
if [ $[$guoqing-$now] -eq 0 ];then
break
fi
day=$[$[$guoqing-$now]/86400]
hour=$[$[$guoqing-$now]%86400/3600]
min=$[$[$guoqing-$now]%3600/60]
sec=$[$[$guoqing-$now]%60]
echo "距离国庆节还有:$day天:$hour小时:$min分钟:$sec秒!"
sleep 1
clear
done
echo "国庆节快乐!!!"
3、写一个脚本把一个目录内的所有空文件都删除,最后输出删除的文件的个数。
#!/bin/bash
count=0
read -p "请输入需要删除文件的路径:" path
for i in `find $path -type f`
do
[ ! -s $i ] && rm -f $i && count++
done
echo "总共删除了$count个空白文件!"
4、写一个自动搭建apache服务的脚本
方法1:
函数实现循环输入(不输入ip地址、主机名、数据根目录一直提示输入)
需求:输入一个域名 ——>this is test.cc test page
IP:10.1.1.1
hostname:
root_dir:
#!/bin/bash
fun_hello(){
in_var=''
while [ -z $in_var ]
do
in_put=$1
read -p "$in_put" in_var
done
echo $in_var
}
ip=`fun_hello "请输入你的IP地址:"`
hostname=`fun_hello "请输入你的域名:"`
root_dir=`fun_hello "请输入你的数据根目录:"`
#主机名和ip地址绑定到hosts文件里
cat >>/etc/hosts<
$ip $hostname
end
#创建相应的数据根目录和首页文件
[ ! -d $root_dir ] && mkdir -p $root_dir || chown -R apache. $root_dir
echo "this is test.cc test page " >$root_dir/index.html
#发布虚拟主机
cat >> /etc/httpd/conf/httpd.conf < NameVirtualHost *:80
ServerAdmin [email protected]
DocumentRoot $root_dir
ServerName $hostname
ErrorLog logs/dummy-host.example.com-error_log
CustomLog logs/dummy-host.example.com-access_log common
end
#启动服务
service httpd restart &>/dev/null
#测试验证
方法2:
while或until循环