Shell编程—结构化命令(2)
1for命令
for命令的基本格式:
for var in list do commands done
在list参数中,你需要提供迭代中要用到的一系列值。
1.1读取列表中的值
例子:
$ vim test1 #!/bin/bash # testing the for variable after the looping for test in Alabama Alaska Arizona Arkansas California Colorado do echo "The next state is $test" done echo "The last state we visited was $test" test=Connecticut echo "Wait, now we're visiting $test" 执行结果: $ ./test1 The next state is Alabama The next state is Alaska The next state is Arizona The next state is Arkansas The next state is California The next state is Colorado The last state we visited was Colorado Wait, now we're visiting Connecticut
1.2读取列表中的复杂值
看这个例子:
$ vim test2 #!/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 结果: $ ./test2 word:I word:don't word:know word:if word:this'll word:work
for循环每个值都是用空格分割的。如果有包含空格的数据值,也会导致这种类似的问题,所以处理方法可以采用上面的第二种(加引号)的方式。
1.3从变量读取列表
看例子:
$ vim test4 #!/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 结果: $ ./test4 Have you ever visited Alabama? Have you ever visited Alaska? Have you ever visited Arizona? Have you ever visited Arkansas? Have you ever visited Colorado? Have you ever visited Connecticut?
1.4从命令读取值
$ vim test5 #!/bin/bash # reading values from a file file="states" for state in $(cat $file) do echo "Visit beautiful $state" done $ cat states Alabama Alaska Arizona Arkansas Colorado Connecticut Delaware Florida Georgia 执行结果: $ ./test5 Visit beautiful Alabama Visit beautiful Alaska Visit beautiful Arizona Visit beautiful Arkansas Visit beautiful Colorado Visit beautiful Connecticut Visit beautiful Delaware Visit beautiful Florida Visit beautiful Georgia
1.5更改字段分隔符
IFS叫作内部字段分隔符
IFS环境变量定义了bash shell用作字段分隔符的一系列字符。默认情况下,bash shell会将下列字符当作字段分隔符:
- 空格
- 制表符
- 换行符
如果bash shell在数据中看到了这些字符中的任意一个,它就会假定这表明了列表中一个新数据字段的开始。
但是我们可以在shell脚本中临时更改IFS环境变量的值来限制被bash shell当作字段分隔符的字符。例如,如果你想修改IFS的值,使其只能识别换行符,那就必须这么做:
IFS=$'\n'
将这个语句加入到脚本中,告诉bash shell在数据值中忽略空格和制表符。对前一个脚本使用这种方法,将获得如下输出。
$ vim test5b #!/bin/bash # reading values from a file file="states" IFS=$'\n' for state in $(cat $file) do echo "Visit beautiful $state" done $ ./test5b Visit beautiful Alabama Visit beautiful Alaska Visit beautiful Arizona Visit beautiful Arkansas Visit beautiful Colorado Visit beautiful Connecticut Visit beautiful Delaware Visit beautiful Florida Visit beautiful Georgia Visit beautiful New York Visit beautiful New Hampshire Visit beautiful North Carolina
1.6用通配符读取目录
$ vim test6 #!/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 $ ./test6 /home/rich/test/dir1 is a directory /home/rich/test/myprog.c is a file /home/rich/test/myprog is a file /home/rich/test/myscript is a file /home/rich/test/newdir is a directory /home/rich/test/newfile is a file /home/rich/test/newfile2 is a file /home/rich/test/testdir is a directory /home/rich/test/testing is a file /home/rich/test/testprog is a file /home/rich/test/testprog.c is a file
for命令会遍历/home/rich/test/*输出的结果。该代码用test命令测试了每个条目(使用方括号方法),以查看它是目录还是文件。for后面可以接多个需要循环遍历的路径。注意这里的判断条件“$file”用引号包围起来了,这是为了避免我们目录名和文件名有空格而导致误认为有多个文件而出错。
2 C语言风格的for命令
例一:使用单一变量
$ vim test8 #!/bin/bash # testing the C-style for loop for (( i=1; i <= 10; i++ )) do echo "The next number is $i" done $ ./test8 The next number is 1 The next number is 2 The next number is 3 The next number is 4 The next number is 5 The next number is 6 The next number is 7 The next number is 8 The next number is 9 The next number is 10
例二:使用多个变量
$ vim test9 #!/bin/bash # multiple variables for (( a=1, b=10; a <= 10; a++, b-- )) do echo "$a - $b" done $ ./test9 1 - 10 2 - 9 3 - 8 4 - 7 5 - 6 6 - 5 7 - 4 8 - 3 9 - 2 10 - 1
3while命令
while命令的格式是:
while test command do other commands done
while命令的关键在于所指定的test command的退出状态码必须随着循环中运行的命令而改变。如果退出状态码不发生变化, while循环就将一直不停地进行下去。
$ vim test11 #!/bin/bash # testing a multicommand while loop var1=5 while echo $var1 [ $var1 -ge 0 ] do echo "This is inside the loop" var1=$[ $var1 - 1 ] done $ ./test11 5 This is inside the loop 4 This is inside the loop 3 This is inside the loop 2 This is inside the loop 1 This is inside the loop 0 This is inside the loop -1
while循环会在var1变量等于0时执行echo语句,然后将var1变量的值减一。接下来再次执行测试命令,用于下一次迭代。echo测试命令被执行并显示了var变量的值(现在小于0了)。直到shell执行test测试命令,whle循环才会停止。
4until命令
until命令和while命令工作的方式完全相反。until命令要求你指定一个通常返回非零退出状态码的测试命令。只有测试命令的退出状态码不为0,bash shell才会执行循环中列出的命令。一旦测试命令返回了退出状态码0,循环就结束了。
格式:
until test commands do other commands done
下面是使用until命令的一个例子。
$ vim test12 #!/bin/bash # using the until command var1=100 until [ $var1 -eq 0 ] do echo $var1 var1=$[ $var1 - 25 ] done $ ./test12 100 75 50 25
使用多个测试命令与while一样。
5嵌套循环
在for循环中嵌套for循环的简单例子:
$ vim test14 #!/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 $ ./test14 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
在while循环内部放置一个for循环:
$ vim test15 #!/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 $ ./test15 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
混用until和while循环:
$ vim test16 #!/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 $ ./test16 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
6控制循环
6.1break命令
1. 跳出单个循环
用for循环举例,当然break命令同样适用于while和until循环:
$ vim test17 #!/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" $ ./test17 Iteration number: 1 Iteration number: 2 Iteration number: 3 Iteration number: 4 The for loop is completed
2. 跳出外部循环
有时你在内部循环,但需要停止外部循环。break命令接受单个命令行参数值:
break n
6.2continue命令
continue命令可以提前中止某次循环中的命令,但并不会完全终止整个循环。可以在循环内部设置shell不执行命令的条件。
一个在for循环中使用continue命令的简单例子:
$ vim test21 #!/bin/bash # using the continue command for (( var1 = 1; var1 < 9; var1++ )) do if [ $var1 -gt 3 ] && [ $var1 -lt 6 ] then continue fi echo "Iteration number: $var1" done $ ./test21 Iteration number: 1 Iteration number: 2 Iteration number: 3 Iteration number: 6 Iteration number: 7 Iteration number: 8
同样地,continue命令也有像break一样的另外两中用法,我们来看一下
continue n