一、循环语句

什么是循环语句?

      实现重复计算和操作的语句。即解决循环问题的语句。许多高级语言中都有好几种循环语句。

      一般均设置一个退出或进入循环的条件来控制循环的次数

bash中的循环控制语句:

      for,while,until


1、for

for循环语法:w

for 变量名 in 列表

    do                                

        循环体                          #do和循环体可以写在同一行,但减少可读性

   done

for,do,done  加;分隔也可以写在同一行

进入条件:列表非空

退出条件:列表遍历结束

运行特性:

      第一遍:将列表中的第一个元素赋值“变量名”定义的变量,而后执行完成循环体;

      第二遍:、、、直到元素遍历结束,循环退出 

列表的生成方式:

      1、直接列出  如: stu100 stu101 stu102  或{stu100,stu101,stu102}

      2、生成整数列表  如:{start_num..end_num} 例:{1..10} 特定格式,表示1到10

      3、使用文件名通配的机制生成列表

      4、使用命令的结果生成

                 seq LAST                #从1开始,不是0

                 seq FIRST LAST

                 seq FIRST STEP LAST  

[root@Node3 src]# cat test2.sh 
for i in {1..10}
do
   echo $i
done
[root@Node3 src]# bash test2.sh
1
2
3
4
5
6
7
8
9
10
[root@Node3 src]# for i in `seq 5`;do echo $i;done
1
2
3
4
5

显示/etc/passwd文件中偶数行用户的用户名。

[root@Node3 src]# cat test4.sh 
line=`cat /etc/passwd|wc -l`
for i in `seq 2 2 $line`
do 
    echo `head -$i /etc/passwd|tail -1|cut -d: -f1`
done
[root@Node3 src]#

2、循环语句while,until

         特别适用于循环次数未知的场景,

while

语法:

     while CONDITION

      do   循环体

             控制变量的修正表达式

      done

进入条件:当CONDITON为“真”

退出条件:当CONDITION为“假”


until

语法:

    until CONDITION

     do  循环体

           控制变量的修正表达式

    done

进入条件:当CONDITION为“假”时

退出条件:当CONDITION为“真”时


3、循环控制

continue [N]:提前结束本次循环,而直接进入下一轮

break [N]:提前结束循环

    后面接数字N表示跳过或结束本循环和外面的父循环总共N个循环


4、死循环

语法1:

 while true   # 这里true写":"也可以

  do 循环体

   if CONDITION

   then  break

   fi

 done

语法2:

 until false

   do 循环体

     if CONDITION

     then  break

     fi

   done

就是一直循环直到某个条件出现才结束咯


5、while、for的特殊用法

while循环的特殊用法:

  遍历文件的每一行

语法:

    while read VARIABLE

     do    循环体

    done < /FILENAME


for循环的特殊用法:

语法:

     for ((expr1;expr2;expr3))

     do  循环体

     done


(()):C语言风格的for(())表达式;不支持-eq这类的运算符。不支持-a和-o,支持<=、>=、<、>这类比较符和&&、||

expr1:定义控制变量,并初始赋值

expr2:循环控制条件

expr3:修正控制变量

 

练习:

1、通过键盘提示用户输入字符,将用户输入的小写字母转换为大写,转换一次之后,再次提醒,再输入再转换,直到输入quit推出。

[root@Node3 ~]# cat while.sh 
read -p "Input a word : " word
while [ "$word" != "quit" ]
do  echo $word|tr 'a-z' 'A-Z'
    read -p "Input a word again: " word
done
[root@Node3 ~]# bash while.sh
Input a word : xj
XJ
Input a word again: 12
12
Input a word again: 1234
1234
Input a word again: adfs
ADFS
Input a word again: magedu
MAGEDU
Input a word again: quit

2、提示用户输入一个用户名,如果存在:显示该用户的UID和SHELL信息,否则,显示无此用户,提示用户再次输入,输入quit退出。

[root@Node3 ~]# cat shell3.sh
read -p "Please input a username: " username
while [ "$username" != "quit" ]
do if [ -z "$username" ]
   then  echo "username is null"
   elif  grep -q "^$username\b" /etc/passwd
   then  echo "`grep "^$username" /etc/passwd|cut -d: -f3,7`"
   else  echo "no $username"
   fi
read -p "Please input a username again: " username
done   
[root@Node3 ~]# bash shell3.sh
Please input a username: sb
no sb
Please input a username again: 1 2
no 1 2
Please input a username again: xj
500:/bin/bash
Please input a username again: 
username is null
Please input a username again: quit
[root@Node3 ~]#

3、提供用户输入一个用户名,判断用户是否登录了当前系统,如果没有登录,则停止5s之后,再次判断,知道用户登录系统,显示“用户来了”而后退出

[root@Node3 ~]# cat while3.sh 
read -p "Please a username: " username
while [[ "$username" != quit ]]
do if [ -z "$username" ]
   then echo "username is null"
   elif who|grep -q "^$username"
   then echo "$username login"
   break
   else sleep 5
   fi
done

wKiom1hJOzWydbvmAAGGbYAe7eM117.gif

4、写一个脚本,完成如下任务

1)提示用户输入一个磁盘设备文件路径;如果用户给定的路径文件不存在或不是一个块设备文件,则提示用户重新输入,知道输入正确为止,或者输入quit以9为退出码结束脚本

 2)提示用户“下面的操作会清空磁盘中的数据,并提问是否继续”,如果用户给出字符y或单词yes,则继续,否则,则提供以8为退出码结束脚本

 3)将用户指定的磁盘上的分区清空,而后创建两个主分区,大小分别为100M和512M

 4)格式化此两个分区

 5)将第一个分区挂载至/mnt/boot目录,第二个分区挂载至/mnt/sysroot目录


练习:

1、计算1到100之内正整数的和

for:

[root@Node3 ~]# declare -i sum=0;for i in {1..100};do sum+=i;done;echo $sum
5050

while:

[root@Node3 ~]# declare -i sum=0;declare -i i=0;while [ $i -le 100 ];do sum+=$i;let i++;done;echo $sum
5050

until:

[root@Node3 ~]# declare -i sum=o;declare -i i=0;until [ $i -gt 100 ];do sum+=i;let i++;done;echo $sum
5050

2、求100以内偶数(奇数)之和

for:

[root@Node3 ~]# declare -i sum=0;for i in `seq 2 2 100`;do sum+=i;done;echo $sum
2550
[root@Node3 ~]# declare -i sum=0;for i in `seq 1 2 100`;do sum+=i;done;echo $sum
2500
[root@Node3 ~]# declare -i sum=0;declare -i i=0;for i in `seq 100`;do if [ $[i%2] -eq 0 ];then sum+=i;let i++;fi;done;echo $sum
2550
[root@Node3 ~]# declare -i sum=0;declare -i i=0;for i in `seq 100`;do if [ $[i%2] -eq 0 ];then continue;else sum+=i;let i++;fi;done;echo $sum
2500

while:

[root@Node3 ~]# declare -i sum=0;declare -i i=0;while [ $i -le 100 ];do  sum+=i;i+=2;done;echo $sum
2550
[root@Node3 ~]# declare -i sum=0;declare -i i=1;while [ $i -le 100 ];do  sum+=i;i+=2;done;echo $sum
2500

until:

[root@Node3 ~]# declare -i sum=0;declare -i i=0;until [ $i -gt 100 ];do if [ $[i%2] -eq 0 ];then sum+=i;fi;let i++;done;echo $sum
2550
[root@Node3 ~]# declare -i sum=0;declare -i i=0;until [ $i -gt 100 ];do if [ $[i%2] -ne 0 ];then sum+=i;fi;let i++;done;echo $sum
2500

3、打印九九乘法表

[root@Node3 ~]# declare -i i=0;declare -i j=0;for i in {1..9};do for j in `seq $i`;do echo -n "$j*$i=$[i*j] ";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
[root@Node3 ~]# cat test3.sh 
declare -i i=1
declare -i j=1
while [ $i -le 9 ]
do while [ $j -le $i ]
     do echo -n "$j*$i=$[i*j] "
     let j++
     done
echo
let i++
j=1      #注意这里每次i循环要将j归1
done
[root@Node3 ~]# bash test3.sh
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

例:

   每隔3秒查看当前系统上是否有名为“gentoo”的用户登录

   如果登录了,则显示gentoo已经登录;如果未登录就显示仍未登录,并显示这是第几次查看了

[root@BAIYU_110 shell]# cat 12.sh
#!/bin/bash   # 用变量替换“gentoo”和相应的命令就可以实现服务或用户上线下线提醒  
#
declare -i i=0
while true;do
     if who|grep "gentoo" &>/dev/null;then
        echo "The gentoo is logged"
        break
     fi
     let i++
     echo "$i gentoo is not login"
     sleep 3
done
[root@BAIYU_110 shell]# bash 12.sh
1 gentoo is not login
2 gentoo is not login
3 gentoo is not login
4 gentoo is not login
5 gentoo is not login
6 gentoo is not login
7 gentoo is not login
8 gentoo is not login
^C

例:找出UID为偶数的所有用户,显示其用户名和UID

[root@Node3 ~]# cat while4.sh
while read line
do if [[ `echo $line|cut -d: -f3`%2 -eq 0 ]]
   then echo `echo $line|cut -d: -f1`
   fi
done</etc/passwd

[root@Node3 ~]# 


[root@BAIYU_110 shell]# cat 13.sh
#!/bin/bash
#
while read line;do
      userid=$(echo $line|cut -d: -f3)
      if [ $[$userid%2] -eq 0 ];then
         echo $line | cut -d: -f1,3
      fi
done</etc/passwd
[root@BAIYU_110 shell]# bash 13.sh
root:0
daemon:2
mail:8
haldaemon:68
ntp:38
sshd:74
tcpdump:72
gentoo:500

例:求100以内所有正整数之和

[root@BAIYU_110 shell]# cat 14.sh
#!/bin/bash
for ((i=1;i<=100;i++));do  # 在这种特定格式下数字比较也可以直接使用<=号了
    let sum+=$i
done
echo "The sum is $sum"
[root@BAIYU_110 shell]# bash 14.sh
The sum is 5050
[root@Node3 ~]# declare -i sum=0;for ((i<=100));do sum+=i;let i++;done;echo $sum
-bash: syntax error: arithmetic expression required
-bash: syntax error: `((i<=100))'
0
[root@Node3 ~]# declare -i sum=0;for ((i<=100;));do sum+=i;let i++;done;echo $sum
-bash: syntax error: arithmetic expression required
-bash: syntax error: `((i<=100;))'
0
[root@Node3 ~]# declare -i sum=0;for ((i=0;i<=100));do sum+=i;let i++;done;echo $sum
-bash: syntax error: arithmetic expression required
-bash: syntax error: `((i=0;i<=100))'
0
[root@Node3 ~]# declare -i sum=0;for ((i=0;i<=100;));do sum+=i;let i++;done;echo $sum
5050
[root@Node3 ~]# declare -i sum=0;for ((i=0;i<=100;));do sum+=i;let i++;done;echo $sum
5050

while和until也可以使用类似的格式:

[root@Node3 ~]# declare -i sum=0;declare -i i=0;while ((i<=100));do sum+=i;let i++;done;echo $sum
5050
[root@Node3 ~]# declare -i sum=0;while ((i=0;i<=100;i++));do sum+=i;done;echo $sum
#while和until不能像for一样在(( ))里面,修正变量
-bash: ((: i=0;i<=100;i++: syntax error: invalid arithmetic operator (error token is ";i<=100;i++")
0
[root@Node3 ~]# declare -i sum=0;declare -i i=0;until ((i>100));do sum+=i;let i++;done;echo $sum
5050

打印九九乘法表

[root@BAIYU_110 shell]# cat 15.sh
#!/bin/bash
#
for ((x=1;x<=9;x++));do       
    for ((y=1;y<=$x;y++));do
       echo -n -e "${y}x${x}=$[$y*$x]\t"
    done
    echo
done
[root@BAIYU_110 shell]# bash 15.sh
1x1=1
1x2=2   2x2=4
1x3=3   2x3=6   3x3=9
1x4=4   2x4=8   3x4=12  4x4=16
1x5=5   2x5=10  3x5=15  4x5=20  5x5=25
1x6=6   2x6=12  3x6=18  4x6=24  5x6=30  6x6=36
1x7=7   2x7=14  3x7=21  4x7=28  5x7=35  6x7=42  7x7=49
1x8=8   2x8=16  3x8=24  4x8=32  5x8=40  6x8=48  7x8=56  8x8=64
1x9=9   2x9=18  3x9=27  4x9=36  5x9=45  6x9=54  7x9=63  8x9=72  9x9=81
[root@BAIYU_110 shell]#


二、read和shift

1、read命令

      read 是从输入文件或者标准输入中或cat等输出的信息中,每次读取一行进行处理。

read命令使用格式:

      read [OPTIONS] VAR...

                -p:输出一句话来当作提示

                -t:等待多少秒后退出

                -n:当接收的字符达到预定数目时,自动退出,并将输入的值赋值给变量

                -s:隐藏输入数据,适用于机密信息的输入

[root@BAIYU_207 shell]# read -p "please enter yourname: " name
please enter yourname: xxj
[root@BAIYU_207 shell]# echo $name
xxj
[root@BAIYU_207 shell]# read -t 5 -p "please enter yourname: " name     
please enter yourname: [root@BAIYU_207 shell]# 
[root@BAIYU_207 shell]# echo $name

[root@BAIYU_207 shell]# read -n 2 -p "please enter yourname: " name     
please enter yourname: xx[root@BAIYU_207 shell]# echo $name
xx 
[root@BAIYU_207 shell]# read -s -p "please enter yourname: " name
please enter yourname: [root@BAIYU_207 shell]# echo $name
xxj

       在read命令行中也可以不指定变量,如果不指定变量,那么read命令会将接收到的数据放置在环境变量REPLY中

环境变量REPLY中包含输入的所有数据,可以像使用其他变量一样在shell脚本中使用环境变量REPLY.

[root@BAIYU_207 shell]# read -t 5 -p "please enter yourname: "  
please enter yourname: xxj
[root@BAIYU_207 shell]# echo $REPLY
xxj

       在上面read后面的变量只有name一个,也可以有多个,这时如果输入多个数据,则第一个数据给第一个变量,第二个数据给第二个变量,如果输入数据个数过多,则最后所有的值都给最后一个变量。如果输入不够则后面的变量为空

[root@BAIYU_207 shell]# read  -p "please enter yourname: " name1 name2 name3
please enter yourname: aa bb cc dd ee
[root@BAIYU_207 shell]# echo $name1
aa
[root@BAIYU_207 shell]# echo $name2
bb
[root@BAIYU_207 shell]# echo $name3
cc dd ee

2、位置参数轮替(shift)

计算给定参数的和?

[root@Node3 ~]# cat shift.sh 
declare -i sum=0
for i in `seq 1 $#`
do 
    let sum+=$1
    shift
done
echo $sum
[root@Node3 ~]# bash shift.sh 1 2 3
6
[root@Node3 ~]# bash shift.sh  2 4 6
12