文章目录
更多的结构化命令
for 命令
for var in list
do
commands
done
for var in list;do
commands
done
读取列表中的值
#!/bin/bash
# basic for command
for test in Alabama Alaska Arizona Arkansas California Colorado
do
echo The next state is $test
done
读取列表中的复杂值
#!/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
word:I
word:dont know if thisll
word:work
有两种办法可解决这个问题:
- 使用转义字符(反斜线)来将单引号转义;
- 使用双引号来定义用到单引号的值。
记住, 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
从命令读取值
#!/bin/bash
# reading values from a file
file="states"
for state in $(cat $file)
do
echo "Visit beautiful $state"
done
更改字段分隔符
IFS环境变量定义了bash shell用作字段分隔符的一系列字符。默认情况下, bash shell会将下列字符当作字段分隔符:
- 空格
- 制表符
- 换行符
在处理代码量较大的脚本时,可能在一个地方需要修改IFS的值,然后忽略这次修改,在脚本的其他地方继续沿用IFS的默认值。一个可参考的安全实践是在改变IFS之前保存原
来的IFS值,之后再恢复它。这种技术可以这样实现:
IFS.OLD=
I
F
S
I
F
S
=
IFS IFS=
IFSIFS=‘\n’
<在代码中使用新的IFS值>
IFS=$IFS.OLD
这就保证了在脚本的后续操作中使用的是IFS的默认值。
#!/bin/bash
# reading values from a file
file="states"
IFS.OLD=$IFS
IFS=$'\n'
for state in $(cat $file)
do
IFS=$IFS.OLD
echo "Visit beautiful $state"
done
用通配符读取目录
最后,可以用for命令来自动遍历目录中的文件。进行此操作时,必须在文件名或路径名中使用通配符。它会强制shell使用文件扩展匹配。文件扩展匹配是生成匹配指定通配符的文件名或路径名的过程。
#!/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
在Linux中,目录名和文件名中包含空格当然是合法的。要适应这种情况,应该将$file变量用双引号圈起来。如果不这么做,遇到含有空格的目录名或文件名时就会有错误产生。
注意,你可以在数据列表中放入任何东西。即使文件或目录不存在, for语句也会尝试处理列表中的内容。在处理文件或目录时,这可能会是个问题。你无法知道你正在尝试遍历的目录是否存在:在处理之前测试一下文件或目录总是好的。
C 语言风格的 for 命令
for (( variable assignment ; condition ; iteration process ))
注意,有些部分并没有遵循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
使用多个变量
#!/bin/bash
# multiple variables
for (( a=1, b=10; a <= 10; a++, b-- ))
do
echo "$a - $b"
done
while 命令
while命令允许定义一个要测试的命令,然后循环执行一组命令,只要定义的测试命令返回的是退出状态码0。它会在每次迭代的一开始测试test命令。在test命令返回非零退出状态码时, while命令会停止执行那组命令。
while test command
do
other commands
done
#!/bin/bash
# while command test
var1=10
while [ $var1 -gt 0 ]
do
echo $var1
var1=$[ $var1 - 1 ]
done
使用多个测试命令
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
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
until 命令
until命令和while命令工作的方式完全相反。 until命令要求你指定一个通常返回非零退出状态码的测试命令。只有测试命令的退出状态码不为0, bash shell才会执行循环中列出的命令。一旦测试命令返回了退出状态码0,循环就结束了。
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
嵌套循环
循环语句可以在循环内使用任意类型的命令,包括其他循环命令。这种循环叫作嵌套循环( nested loop)。注意,在使用嵌套循环时,你是在迭代中使用迭代,与命令运行的次数是乘积关系。不注意这点的话,有可能会在脚本中造成问题。
#!/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
控制循环
你可能会想,一旦启动了循环,就必须苦等到循环完成所有的迭代。并不是这样的。有两个命令能帮我们控制循环内部的情况:
- break命令
- continue命令
break 命令
跳出单个循环
在shell执行break命令时,它会尝试跳出当前正在执行的循环。
#!/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"
跳出内部循环
在处理多个循环时, 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
跳出外部循环
有时你在内部循环,但需要停止外部循环。 break命令接受单个命令行参数值:
break n
#!/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
continue 命令
continue命令可以提前中止某次循环中的命令,但并不会完全终止整个循环。可以在循环内部设置shell不执行命令的条件。
#!/bin/bash
# using the continue command
for (( var1 = 1; var1 < 15; var1++ ))
do
if [ $var1 -gt 5 ] && [ $var1 -lt 10 ]
then
continue
fi
echo "Iteration number: $var1"
done
和break命令一样, 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
处理循环的输出
最后,在shell脚本中,你可以对循环的输出使用管道或进行重定向。这可以通过在done命令之后添加一个处理命令来实现。
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
shell会将for命令的结果重定向到文件output.txt中,而不是显示在屏幕上。
这种方法同样适用于将循环的结果管接给另一个命令。
#!/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"