前面介绍了if和case语句,这一节我们了解for、while和until语句
1、for命令
对命令进行重复执行,是编程思想中的常见方式。
bash shell提供了for命令,来重复执行一组命令:
for var in list
do
commands
done
参数list用于提供一些用于迭代的值。
1.1、读取列表中的值
给变量test轮流复制;
#!/bin/bash #basic for command for test in Alabama Alaska Alaska Arizona Arkansas California Colorado do echo The next state is $test done
最后一个值,colorado赋值完成以后,会继续向下运行脚本程序
#!/bin/bash #testing the for variable after the looping for test in Alabama Alaska Ariziona Arkansas California Colorado do echo "The next state is $test" done echo "The last state we visited was $test" test=Connecticut ehco "Wait,now we're visiting $test"
1.2、读取列表中的复杂值
事情不会那么简单,以下实例说明一个麻烦:
#!/bin/bash #another example of how not to use the fo command for test in I don't know if this'll work do echo "word:$test" done
其中 't know if this' 被识别为了一个字符串,同时赋值给了test
解决方法:1、使用转意字符;2、使用双引号来定义使用的单引号的值;
#!/bin/bash #another example of how not to use the for command for test in I don't know if "this'll" work do echo "word:$test" done
所以,我们需要技术,for循环中每个值都是用空格隔开的。我们就需要用双引号引起来;
#!/bin/bash #an example of how to properly define values for test in Nevada "New Hampshire" "New Mexico" "New York" do echo "Now going to $test" done
1.3、从变量读取列表
我们会将列表存储于变量中,让for语句从变量中读取数据;
#!/bin/bash #using a variable to hold the list list="Alabama Alaska Arizona Arkansas Colorado" list=$list" Connecticut" for state in $list do echo "Have you ever visited $state?" done
1.4、读取命令中的值
可以使用反引号来获取命令执行结果,赋值给变量,再对变量进行遍历;
#!/bin/bash #reading values from a file file="states" for state in `cat $file` do echo "Visit beautiful $state" done
这里注意,states文件中的内容,每一行包含一个转态,用空格隔开。
1.5、改变字段分隔符
默认使用空格做分隔符。但是根据IFS--内部字段分割符包括三个:空格、制表符、换行符。
如何选择其他的符号作为分隔符呢,或者是同时使用多个符号做分隔符呢?
#!/bin/bash #reading values from a file file="states" IFS=$` ` #IFS值来定义分隔符,可以通过该命令,来改变分隔符; 表示以回车为分隔符 for state in `cat $file` do echo "Visit beautiful $state" done
在工作中对于分隔符的定义方法,先保存原来的分隔符,等在使用时候恢复过来即可
IFS.OLD=$IFS IFS=$` ` <user teh new IFS value in code> IFS=$IFS.OLD
如果想指定多个分隔符
IFS=$`
`:;" #这里使用了回车、冒号、分号、双引号同时作为分隔符
1.6、使用通配符读取目录
文件通配符匹配目录
#!/bin/bash #iterate through all the files in a directory for file in /home/rich/test/* do if [ -d "$file" ] #判断文件是否为目录 then echo "$file is a directory" elif [ -f "$file" ] #判断是否为普通文件 then echo "$file is a file" fi done
可以出了使用通配符,还可以结合列表
#!/bin/bash #iterating through multiple directories for file in /home/rich/.b* /home/rich/badtest do if [ -d "$file" ] then echo "$file is a directory" elif [ -f "$file" ] then echo "$file is a file" else echo "$file doesn't exist" fi done
2、C式的for命令
在C语言中,for循环通常定义一个变量,该变量在每次迭代过程中自动改变值。通常程序员将该变量用做计数器,每次迭代计数器要么增加一个,要么减少一个。bash的for命令也能提供这种功能。
2.1、C语言中的for命令
在C语言的循环中,for一直要保持true才能继续运行,直到false,则循环结束
for (i = 0; i < 10; i++) { printf("The next number is %d ", i); }
i作为计数器。一直累加,当不符合条件时循环结束;
bash shell可以使用这种思路,来编写自己的for循环脚本语句;
格式:for (( variable assignment ; condition ; iteration process ))
for (( a=1; a<10; a++ ))
注意,有几项是不遵循bash shell的for方法:1、变量的复制可以包含空格;2、条件中的变量不以$符号做前缀;3、迭代处理式不适用expr命令格式;
在shell脚本中,使用C式的程序需要谨慎;
#!/bin/bash #testing the C-style for loop for (( i=1; i <= 10; i++)) do echo "The next number is $i" done
2.2、使用多个变量
C式的shell只能在for循环中定义一个条件,是具有局限性的;
#!/bin/bash #multiple variables for (( a=1, b=10; a <=10 ' a++, b--)) do echo "$a - $b" done
3、while命令
while命令像是if-then和for的结合体。while是容许要定义测试的命令,只要定义的测试命令返回值为0,就循环一组命令。它在每次迭代开始时检查测试命令,测试命令返回值为非零,while则终止执行命令集;
3.1、while基本格式
while命令的格式:
while test command
do
other commands
done
在while语句中,test与if-then语句中的定义格式一样;while的关键是,在运行other commands后一点要改变test转态,否则就会进入死循环;
#!/bin/bash #while command test var1=10 while [ $var1 -gt 0 ] #比较var1值与0的大小 do echo $var1 var1=$[ $var1 - 1 ] #每次循环完成都要对var1参数减1才行 done
3.2、使用多条测试命令
while语句容许定义多条test命令。只有最后一条test命令的状态才决定循环何时停止;
#!/bin/bash # testing a multicommand while loop var1=10 while echo $var1 [ $var1 -ge 0 ] do echo "This is inside the loop" var1=$[ $var1 - 1 ] done
上面的这个脚本中while的测试语句有两条,ehco $var1和[ $var1 -ge 0 ],所以,最后是否运行do-done中的命令,取决于 [ $var1 -ge 0 ] 这条命令的测试结果
4、until命令
until命令刚好和while命令相反。定义一个测试语句,如果返回为非0结果,则运行do-done中的语句,如果是0结果,则不运行do-done中的语句;
until命令的格式:
until test commands
do
other commands
done
与while类似,可以使用多条测试语句,但是依然只有最后条测试语句才生效;
#!/bin/bash # using the until command var1=100 until [ $var1 -eq 0 ] do echo $var1 var1=$[ $var1 - 25 ] done
一旦结果变为0,则运行结果停止。
#!/bin/bash #using the until command var1=100 until echo $var1 [ $var1 -eq 0 ] do echo Inside the loop: $var1 var1=$[ $var1 -25 ] done
5、嵌套循环
一条循环语句可以在循环中使用任何类型的命令,包括其他循环的命令,就是嵌套循环。
一个for循环中嵌套另一个for循环实例:
#!/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
for循环放在while循环内:
#!/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 ] done
until和while循环也是可以结合起来:
#!/bin/bash # using until and while loops var1=3 until [ $var1 -eq 0 ] #从3开始,只要不等于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 ] #执行完一次,我们需要对var1 - 1 不能一直循环下去 done
6、文件数据的循环
迭代存储在文件内部的项,需要结合两种介绍过的技术:1、使用嵌套循环;2、更改环境变量IFS;
通过更改环境变量IFS,可以迫使for命令将文件中的每行作为单独的一项来处理,即使数据含有空格。提取了文件中的个别行之后,您可能还需要再循环已提取其宝行的数据;
以/etc/passwd文件中处理数据为例:
#!/bin/bash # changing the IFS value IFS.OLD=$IFS IFS=$` ` for entry in `cat /etc/passwd` do echo "Values in $entry -" IFS=: for value in $entry do echo "$value" done done
先取出每行,在再每行上以:为分隔符在取一遍数值;
7、控制循环
我们可以通过命令控制循环内部发生的事情。1、break;2、continue;
这两条命令用于控制循环操作;
7.1、break
在循环的过程中,跳出循环的一种简单方法。可以使用break退出任何类型的循环;
1、跳出单循环
#!/bin/bash # breaking out of a for loop for var1 in 1 2 3 4 5 6 7 8 9 10 do if [ $var1 -eq 5 ] then break fi echo "Iteration number: $var1" done echo "The for loop is completed"
for循环通常迭代列表中指定的所有值。然而,当if-then条件满足,shell执行break命令就能终止for循环;这种方式同样适用于while和until循环;
#!/bin/bash # breaking out of a while loop var1=1 while [ $var1 -lt 10 ] do if [ $var1 -eq 5 ] then break fi echo "Iteration: $var1" var1=$[ $var1 + 1 ] done echo "The while loop is completed"
2、跳出内循环
使用多循环时break命令自动终止您所在的最里面的内部循环;
#!/bin/bash # breaking out of an inner loop for (( a = 1; a < 4; a++ )) do echo "Outer loop: $a" for (( b = 1; b < 100; b++ )) do if [ $b -eq 5 ] then break fi echo " Inner loop: $b" done done
3、跳出外循环
可能有时处于内循环单需要停止外循环。break命令宝行单独的命令执行参数;
#!/bin/bash # breaking out of an outer loop for (( a = 1; a < 4; a++ )) do echo "Outer loop: $a" for (( b = 1; b < 100; b++ )) do if [ $b -gt 4 ] then break 2 fi echo " Inner loop: $b" done done
这里 2 数据表示循环级别,当前所处的 循环级别为 1 ;向外一次加。就是 2级循环;
7.2、continue
不终止循环,只是跳过这一个循环值,后面的依然继续运行;
for循环中使用continue
#!/bin/bash # using the contnue command for (( var1 = 1; var1 < 15; var1++ )) do if [ $var -gt 5 ] && [ $var1 -lt 10 ] then continue fi echo "Iteration number: $var1" done
var1值大于5小于10的话,就被continue跳过了;
在until和while中使用continue要特别谨慎,不能在键值添加的时候跳过这个添加值的过程;
#!/bin/bash # improperly using the continue command in a while loop var1=0 while echo "while iteration: $var1" [ $var1 -lt 15 ] do if [ $var1 -gt 5 ] && [ $var1 -lt 10 ] then continue fi echo "Inside iteration number: $var1" var1=$[ $var1 + 1 ] done
在大于5小于10的时候跳过了var1自加的过程,则时候就进入了死循环!!!这一点一定要注意;
同样的,continue命令可以使用 continue n 来指定停止的循环级别;
#!/bin/bash # continuing an outer loop for (( a = 1; a <= 5; a++ )) do echo "Iteration $a:" for (( b = 1; b < 3; b++ )) do if [ $a -gt 2 ] && [ $a -lt 4 ] then continue 2 fi var3=$[ $a * $b ] echo " The result of $a * $b is $var3" done done
8、处理循环输出
最后,在shell循环中,使用管道和重定向符号处理输出结果;
for file in /home/rich/* do if [ -d "$file" ] then echo "$file is a directory" elif echo "$file is a file" fi done > output.txt
可以将脚本内容重定向到output.txt中,而不是输出到屏幕
#!/bin/bash # redirecting the for output to a file for (( a = 1; a < 10; a++ )) do echo "The number is $a" done > test23.txt echo "The command is finished."
同样的技术,也可以用于将循环的输出管道传送给其他命令:
#!/bin/bash # piping a loop to another command for state in "North Dakota" Connecticut Illinois Alabama Tennessee do echo "$state is the next place to go" done | sort echo "This completes our travels"
for输出的结果传送给sort来进行操作;