[TOC]
1. for命令
bash shell提供了for命令,允许你创建一个遍历一系列值的循环。每次迭代都使用其中一个值来执行已定义好的一组命令。下面是bash shell中for命令的基本格式。
for var in list
do
commands
done
在list参数中,你需要提供迭代中要用到的一系列值。在每次迭代中,变量var会包含列表中的当前值。在do和done语句之间输入的命令可以是一条或多条标准的bash shell命令。在这些命令中,$var变量包含着这次迭代对应的当前列表项中的值。
1.1 读取列表中的值
for命令最基本的用法就是遍历for命令自身所定义的一些列值。
#!/bin/bash
# Basic for command
for test in Alabama Alaska Arizona
do
echo "The next state is $test"
done
每次for命令遍历列表,它都会将列表中的下个值赋给test变量可以像for命令语句中的其他脚本变量一样使用。在最后一次迭代后,$test变量的值会在shell脚本的剩余部分一直保持有效。
1.2 读取列表中的复杂值
1.3 从变量读取列表
通常shell脚本遇到的情况是,你将一系列值都集中存储在一个变量中,然后需要遍历变量中的整个列表。
#!/bin/bash
# Using a variable to hold the list.
list="Alabama Alaska Arizona"
list=$list" Connecticut"
for state in $list
do
echo "Visit $state."
done
./test1_3.sh
Visit Alabama.
Visit Alaska.
Visit Arizona.
Visit Connecticut.
$list中包含了用于迭代的标准文本值列表。
1.4 从命令读取值
生成列表中值的另一个途径就是使用命令的输出。可以用命令替换来执行任何能产生输出的命令,然后在for命令中使用该命令的输出。
#!/bin/bash
# Reading values from a file.
#
file="states.txt"
IFS=$'\n'
for state in $(cat $file)
do
echo "Visit $state."
done
./test1_4.sh
Visit Alabama.
Visit Alaska.
Visit New York.
Visit North Carolina.
这个例子中使用了cat命令来输出文件states.txt中的内容。
1.5 更改字段分隔符
IFS(internal field separator)叫作内部字段分隔符,IFS环境变量定义了bash shell用作字段分隔符的一系列字符。默认情况下,bash shell会将下列字符当作字段分隔符:
- 空格
- 制表符
- 换行符
如果bash shell在数据中看到了这些字符中的任意一个,它就会假定这表明了列表中一个新数据字段的开始。在处理可能包含有空格的数据时,这会比较麻烦。要解决这个问题,可以在shell脚本中临时更改IFS环境变量的值来限制被bash shell当作字段分隔符的字符。例如,如果你想修改IFS的值,使其只能识别换行符,那就必须这么做:
IFS=$'\n'
将这个语句加入到脚本中,告诉bash shell在数据值中忽略空格和制表符。
#!/bin/bash
# Reading values from a file.
#
file="states.txt"
IFS=$'\n'
for state in $(cat $file)
do
echo "Visit $state"
done
cat states.txt
Alabama
Alaska
New York
North Carolina
./test1_5.sh
Visit Alabama
Visit Alaska
Visit New York
Visit North Carolina
1.6 用通配符读取目录
可以使用for命令来自动遍历目录中的文件。进行此操作时,必须在文件名或文件路径名中使用通配符。它会强制shell使用文件扩展匹配。文件扩展匹配是生成匹配指定通配符的文件名或路径名的过程。
#!/bin/bash
# Itrate through all the files in a directory.
#
for file in /home/henryhu/bash-study/*
do
if [ -d "$file" ]
then
echo "$file is a directory."
elif [ -f "$file" ]
then
echo "$file is a file."
fi
done
for命令会遍历/home/henryhu/bash-study/*输出的结果。该代码用test命令测试了每个条目(使用方括号方法),以查看它是目录(通过-d参数)还是文件(通过-f参数)。在Linux中,目录名和文件名中包含空格当然是合法的。为了适应这种情况,应该将$file变量用双引号圈起来。
2. C语言风格的for命令
C语言风格的for命令看起来如下:
for ((a = 1; a < 10; a++ ))
注意,有些部分并没有遵循bash shell标准的for命令:
- 变量赋值可以有空格;
- 条件中的变量不以美元符开头;
- 迭代过程的算式未用expr命令格式。
#!/bin/bash
# Testing the C-Style for loop
#
for (( i = 1; i <= 10; i++ ))
do
echo "The next number is $i."
done
for循环通过定义好的变量(本例中是变量i)来迭代执行这些命令。在每次迭代中,$i变量包含了for循环中赋予的值。在每次迭代后,循环的迭代过程会作用在变量上。
3. while命令
while命令某种意义上是if-then语句和for循环的混杂体。while命令允许定义一个要测试的命令,然后循环执行一组命令,只要定义的测试命令返回的是退出状态码0。它会在每次迭代的一开始测试test命令。在test命令返回非零退出状态码时,while命令会停止执行那组命令。
3.1 while基本格式
while命令的格式是:
while test command
do
other commands
done
while命令中定义的test command和if-then语句中的格式一模一样。可以使用任何普通的bash shell命令,或者用test命令进行条件测试,比如测试变量值。
while命令的关键在于所指定的test command的退出状态码必须随着循环中运行的命令而改变。如果退出状态码不发生变化,while循环就将一直不停地进行下去。
#!/bin/bash
# While command test
#
var1=10
while [ $var1 -gt 0 ]
do
echo $var1
var1=$[ $var1 - 1 ]
done
./test3_1.sh
10
9
8
7
6
5
4
3
2
1
while命令定义了每次迭代时检查的测试条件:
while [ $var1 -gt 0 ]
只要测试条件成立,while命令就会不停地循环执行定义好的命令。在这些命令中,测试条件中用到的变量必须修改,否则就会陷入无限循环。
3.2 使用多个测试命令
while命令允许你在while语句行定义多个测试命令。只有最后一个测试命令的退出状态码会被用来决定什么时候结束循环。
#!/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
./test3_2.sh
10
This is inside the loop.
9
This is inside the loop.
8
This is inside the loop.
7
This is inside the loop.
6
This is inside the loop.
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语句中定义了两个测试命令。
while echo $var1
[ $var1 -ge 0 ]
第一个测试简单地显示了var1变量的当前值。第二个测试用方括号来判断var1变量的值。在循环内部,echo语句会显示一条简单的消息,说明循环被执行了。while循环会在var1变量等于0时执行echo语句,然后将var1变量的值减一。接下来再次执行测试命令,用于下一次迭代。echo测试命令被执行并显示了var变量的值。直到shell执行test测试命令,while循环才会停止。
4. until命令
until命令和while命令的工作方式完全相反。until命令要求指定一个通常返回非零退出状态码的测试命令。只有测试命令的退出状态码不为0,bash shell才会执行循环中列出的命令。一旦测试命令返回了退出状态码0,循环就结束了。until命令的格式如下:
until test commands
do
other commands
done
和while命令类似,可以在until命令语句中放入多个测试命令。只有最后一个命令的退出状态码觉定了bash shell是否执行已定义的other commands。
#!/bin/bash
# Using the until command
#
var1=100
until [ $var1 -eq 0 ]
do
echo $var1
var1=$[ $var1 - 25 ]
done
本例中会测试var1变量来决定until循环何时停止。只要该变量的值等于0,until命令就会停止循环。
5. 嵌套循环
循环语句可以在循环内使用任意类型的命令,包括其他循环命令。这种循环叫作嵌套循环(nested loop)。
#!/bin/bash
# Test nested loop
#
for ((a = 1; a <=3;a++ ))
do
echo "Starting loop $a:"
for(( b = 1; b <= 3; b++))
do
echo " Inside loop:$b"
done
done
./test5_1.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
被嵌套的循环(也称为内部循环,inner loop)会在外部循环的每次迭代中遍历一次它所有的值。
6. 处理循环的输出
在shell脚本中,可以对循环的输出使用管道或进行重定向。这可以通过在done命令之后添加一个处理命令来实现。
#!/bin/bash
# Redirecting the for output to a file
#
for ((a = 1; a < 10 ; a++ ))
do
echo "The number is $a."
done > test.txt
echo "The command is finished."
cat test.txt
The number is 1.
The number is 2.
The number is 3.
The number is 4.
The number is 5.
The number is 6.
The number is 7.
The number is 8.
The number is 9.
shell创建了test.txt文件并将for命令的输出重定向到这个文件。shell在for命令之后正常显示了echo语句。