七、循环结构化命令
for命令
创建一个遍历,每次迭代读取列表中的一个值。
迭代完成后,变量会保存最后一次迭代的值。
语法格式
第一种写法
for var in list do 命令 done
第二种写法
for var in list;do 命令 done
第三种写法,c语言风格
for (( i=1;i<=10;i++ )) do echo $i done #或者 for (( i=1;i<=10;i++ )) { echo $i }
取值列表有多种方式,如取in后面的值,默认以空格分隔
举例
[root@tzPC ~]# cat for1.sh #!/bin/bash for var in a b c d do echo "the text is $var" done
列表有复杂值,可以使用引号或者转义字符 \
举例
#!/bin/bash for var in a b "c1 d1" e "hello world" do echo $var done
如果有单引号,还可以使用\转义
[root@tzPC ~]# cat for2.sh #!/bin/bash for var in a b\'1 "c d" e "hello world" I\'s o do echo $var done [root@tzPC ~]# bash for2.sh a b'1 c d e hello world I's o
\会将后面的单引号转义
从变量中取值
#!/bin/bash list="a1 b1 c1 d1" for i in $list do echo is a $i done
从命令中取值
[root@tzPC ~]# cat for3.sh #!/bin/bash for i in `bash for2.sh` do echo $i done
结果
[root@tzPC ~]# bash for3.sh a b'1 c d e hello world I's o
从文件中取值
[root@tzPC 13Unit]# cat test5.sh #!/bin/bash file="file" for var in $(cat $file);do echo $var done
自定义shell分隔符
默认情况下,base shell会以如下做为分隔符。
- 空格
- 制表符
- 换行符
可通环境变量IFS(内部字段分隔符)来自定义为分隔符。
指定单个字符做分隔符:
IFS=: #以:冒号做分隔符 #可以指定多个 如 IFS='\n':;" #这个赋值会将反斜杠、n、冒号、分号和双引号作为字段分隔符。
注:$'\n'与'\n'时的区别
IFS='\n' #将字符\和字符n作为IFS的换行符。
IFS=$'\n' #使用换行符做为字段分隔符。
举例
[root@tzPC ~]# cat for4.sh #!/bin/bash IFS=$'\n' for i in `cat /etc/hosts` do echo $i done [root@tzPC ~]# bash for4.sh 127.0.0.1 localhost localhost.localdomain localhost4 localhost4.localdomain4 ::1 localhost localhost.localdomain localhost6 localhost6.localdomain6
在一个地方修改IFS值,在脚本其他地方沿用IFS默认值
可以先将环境变量IFS的值赋给变量IFS_OLD,注意书中写的是赋值给IFS.OLD变量,在实验环境中会报错。
[root@tzPC 13Unit]# cat test5.sh #!/bin/bash file="file" IFS_OLD=$IFS IFS=$'\n' for var in $(cat $file);do echo $var done IFS=$IFS_OLD for var in 1 2 3 4 5 do echo $var done
使用通配符读取目录
因为目录名跟文件名可能包含空格,所以$file变量名最好使用双引号圈起来。
[root@tzPC temp_script]# cat test6.sh #!/bin/bash for file in /usr/bin/* do if [ -d "$file" ];then echo "$file" is a directory elif [ -f "$file" ];then echo "$file is a file" fi done
也可以列出多个目录通配符
[root@tzPC 13Unit]# cat test6.sh #!/bin/bash for file in /usr/bin/* /etc/* do if [ -d "$file" ];then echo "$file is a directory" elif [ -f "$file" ];then echo "$file is a file" fi done
C语言风格的for命令
[root@tzPC ~]# cat for5.sh #!/bin/bash for (( i=1;i<=10;i++ )) do echo num is $i done [root@tzPC ~]# bash for5.sh num is 1 num is 2 num is 3 num is 4 num is 5 num is 6 num is 7 num is 8 num is 9 num is 10
使用多个变量
举例:同时输出1-9的升序和降序
注意,结束循环条件只要满足其中一条即可,是或关系
[root@tzPC ~]# cat for6.sh #!/bin/bash for (( a=1,b=9;a<10;a++,b-- )) do echo num is $a -$b done [root@tzPC ~]# bash for6.sh num is 1 -9 num is 2 -8 num is 3 -7 num is 4 -6 num is 5 -5 num is 6 -4 num is 7 -3 num is 8 -2 num is 9 -1
如上述脚本改成如下
[root@tzPC temp_script]# cat for6.sh #!/bin/bash for ((a=1,b=9;a<10,b>5;a++,b--)) do echo $a -$b done [root@tzPC temp_script]# bash for6.sh 1 -9 2 -8 3 -7 4 -6
while命令
只要测试条件成立,就重复执行命令
语法格式
while test command do other commands done
最常见的方式是使用方括号来检查循环命令
举例:降序输出10到1的数字
[root@tzPC ~]# cat while1.sh #!/bin/bash var=10 while [ $var -gt 0 ] do echo $var var=$[ $var-1 ]
#或var=$(($var-1))或((var--))的写法都可以 done
举例2:输出如下图两数相乘的结果
自增操作 let var++
自减操作 let var--
[root@tzPC ~]# cat while2.sh #!/bin/bash num=1 while [ $num -lt 10 ] do sum=$(( $num * $num )) echo "$num * $num = $sum" ((num++ )) # let num++ done
使用多个测试命令
while命令可以定义多个测试命令,但只有最后一个测试命令的退出码会被用来决定结束循环。
每条测试命令需独占一行。
[root@tzPC 13Unit]# cat test7.sh #!/bin/bash var1=10 while echo $var1 [ $var1 -ge 0 ] do echo "This is inside the loop" var1=$[ $var1 - 1 ] done
until命令
与while命令工作方式相反,只有测试命令的退出状态码不为0(也就是条件不成立时),才会执行循环体,一旦测试命令返回退出状态码0,循环结束。
同样支持多个测试命令,最后一个测试命令退出码决定是否执行循环体。
语法格式
until test commands do other commands done
举例
[root@tzPC 13Unit]# bash test8.sh 100 75 50 25 [root@tzPC 13Unit]# cat test8.sh #!/bin/bash #using the until command var1=100 until [ $var1 -eq 0 ] #当$var1不等于0时才执行循环 do echo $var1 var1=$[ $var1 -25 ] done
嵌套循环
循环语句可以在循环内使用循环命令,在迭代中使用迭代,与命令运行的次数是乘积关系。
举例for循环嵌套for循环
[root@tzPC 13Unit]# bash test14.sh Starting loop 1: Inside loop:1 Inside loop:2 Inside loop:3 Starting loop 2: Inside loop:1 Inside loop:2 Inside loop:3 Starting loop 3: Inside loop:1 Inside loop:2 Inside loop:3 [root@tzPC 13Unit]# cat test14.sh #!/bin/bash #nesting for loops for (( a = 1; a <= 3; a++ )) do echo "Starting loop $a:" for (( b = 1; b <= 3; b++ )) do echo " Inside loop:$b" done done
while嵌套for循环
[root@tzPC 13Unit]# bash test15.sh Outer loop:5 Inner loop: 5 * 1 =5 Inner loop: 5 * 2 =10 Outer loop:4 Inner loop: 4 * 1 =4 Inner loop: 4 * 2 =8 Outer loop:3 Inner loop: 3 * 1 =3 Inner loop: 3 * 2 =6 Outer loop:2 Inner loop: 2 * 1 =2 Inner loop: 2 * 2 =4 Outer loop:1 Inner loop: 1 * 1 =1 Inner loop: 1 * 2 =2 Outer loop:0 Inner loop: 0 * 1 =0 Inner loop: 0 * 2 =0 [root@tzPC 13Unit]# cat test15.sh #!/bin/bash #placing a for loop inside a while loop var1=5 while [ $var1 -ge 0 ] do echo "Outer loop:$var1" for (( var2 = 1; $var2 <3; var2++ )) do var3=$[ $var1 * $var2 ] echo " Inner loop: $var1 * $var2 =$var3" done var1=$[ $var1 - 1 ]#使用((var1--))方便 done
until嵌套while循环
[root@tzPC 13Unit]# bash test16.sh Outer loop:3 Inner loop:3 / 1 = 3.0000 Inner loop:3 / 2 = 1.5000 Inner loop:3 / 3 = 1.0000 Inner loop:3 / 4 = .7500 Outer loop:2 Inner loop:2 / 1 = 2.0000 Inner loop:2 / 2 = 1.0000 Inner loop:2 / 3 = .6666 Inner loop:2 / 4 = .5000 Outer loop:1 Inner loop:1 / 1 = 1.0000 Inner loop:1 / 2 = .5000 Inner loop:1 / 3 = .3333 Inner loop:1 / 4 = .2500 [root@tzPC 13Unit]# cat test16.sh #!/bin/bash #using until and while loops var1=3 until [ $var1 -eq 0 ] do echo "Outer loop:$var1" var2=1 while [ $var2 -lt 5 ] do var3=$(echo "scale=4;$var1 / $var2" | bc) echo " Inner loop:$var1 / $var2 = $var3" var2=$[ $var2 + 1 ] done var1=$[ $var1 - 1 ] done
循环处理文件数据
注意两点
- 使用嵌套循环
- 修改IFS环境变量
打印/etc/passwd各个字段 [root@tzPC 13Unit]# bash test17.sh Values in root:x:0:0:root:/root:/bin/bash root x 0 0 root /root /bin/bash
脚本如下
[root@tzPC 13Unit]# cat test17.sh #!/bin/bash #changing the IFS value IFS_OLD=$IFS IFS=$'\n' for entry in $(cat /etc/passwd) do echo "Values in $entry " IFS=: for value in $entry do echo " $value" done done
添加user.txt文件中的5个用户。
[root@tzPC ~]# cat useradd.sh #!/bin/bash for name in `cat /root/useradd.txt` do id $name &> /dev/null if [ $? -eq 0 ] ;then echo "user $name created" else useradd $name echo "123456" | passwd --stdin $name &> /dev/null fi done
可以根据添加用户写一个删除用户,自己动手,我已经写出来了哈哈
2020年8月26日复习于此,加油我看好我自己。
打印九九乘法表
注意:外层循环行,内层循环列
规律:第二个变量小于等于第一个变量
seq 9表示从1连续输出到9
[root@tzPC ~]# seq 9 1 2 3 4 5 6 7 8 9
脚本
[root@tzPC ~]# bash for_99.sh 1*1=1 2*1=2 2*2=4 3*1=3 3*2=6 3*3=9 4*1=4 4*2=8 4*3=12 4*4=16 5*1=5 5*2=10 5*3=15 5*4=20 5*5=25 6*1=6 6*2=12 6*3=18 6*4=24 6*5=30 6*6=36 7*1=7 7*2=14 7*3=21 7*4=28 7*5=35 7*6=42 7*7=49 8*1=8 8*2=16 8*3=24 8*4=32 8*5=40 8*6=48 8*7=56 8*8=64 9*1=9 9*2=18 9*3=27 9*4=36 9*5=45 9*6=54 9*7=63 9*8=72 9*9=81 [root@tzPC ~]# cat for_99.sh #!/bin/bash for i in `seq 9` do for j in `seq 9` do [ $j -le $i ] && echo -n "$i*$j=`echo $(($i*$j))` " done echo " " done
学习来自:《Linux命令行与Shell脚本大全 第3版》第13章