for 命令
基本用法
for 可以遍历一系列值,每次迭代都使用其中的一个值来执行一组命令。格式如下:
for var in list
do
commands
done
比如:
$ cat test12
#!/bin/bash
for test in A B C D
do
echo $test
done
echo $test
$ /bin/bash test12
A
B
C
D
D
可以看出执行完后,$test 变量保持了其值,并且在 for 循环外跟其他变量一样使用。
for 循环假定每个值都是空格分隔的,如果某个值中包含空格,我们需要用双引号将它括起来:
$ cat test13
#!/bin/bash
for test in 'A B' "C D"
do
echo $test
done
$ /bin/bash test13
A B
C D
我们也可以从变量读取列表:
#!/bin/bash
list="Xi'an Guangdong Hunan"
list=$list" Connecticut"
for state in $list
do
echo "Have you ever visited $state"
done
我们也可以从命令读取值:
$ cat test14
#!/bin/bash
file="states"
for state in $(cat $file)
do
echo "Visit beautiful $state"
done
$ cat states
Beijing
Guangdong
Xi'an
Hubei
$ /bin/bash test14
Visit beautiful Beijing
Visit beautiful Guangdong
Visit beautiful Xi'an
Visit beautiful Hubei
指定分隔符
注意到 states 中每一行都有一个值,并不是按空格分开的,而 for 每次遍历了一行,说明回车和空格一样也能分隔不同值。这类字符叫 内部字段分隔符(internal field separator),IFS环境变量定义了 bash shell 用作字段分隔符的一系列字符,默认情况下包括:
- 空格
- 制表符
- 换行符
我们可以通过修改 IFS 来指定字段分隔符,比如:
$ cat test15
#!/bin/bash
IFS=$'\n'
for test in A B \n C D
do
echo $test
done
$ /bin/bash test15
A
B
C
D
如果要用多个 IFS,只要把它们串起来即可:
$ cat test16
#!/bin/bash
IFS="\n ;\""
for test in A\;B\"C\nD
do
echo $test
done
$ /bin/bash test16
A B C D
用通配符读取目录
我们可以用 for 来遍历目录中的文件。进行此操作时,必须在文件名或路径名中使用通配符。它会强制 shell 使用文件扩展匹配 。
$ cat file17
#!/bin/bash
for file in /home/pi/*
do
if [ -d "$file" ]
then
echo "$file is a directory"
elif [ -f "$file" ]
then
echo "$file is a file"
fi
done
$ /bin/bash file17
/home/pi/blog is a directory
/home/pi/code is a directory
/home/pi/newfile is a file
for 命令会遍历/home/rich/test/* 输出的结果。该代码用test 命令测试了每个条目(使用方括号方法),以查看它是目录(通过-d 参数)还是文件(通过-f 参数)
注意我们用双引号括住了文件名("$file"
),如果不这么做,遇到含有空格的目录名或文件名时就会有错误产生。
C 风格的 for
bash 中 C 语言风格的 for 循环的基本格式如下:
for (( variable assignment ; condition ; iteration process ))
do
done
比如:
#!/bin/bash
for (( a = 1 ; a < 10 ; a++ ))
do
echo $a
done
C 语言风格的 for 命令也允许为迭代使用多个变量。循环会单独处理每个变量,你可以为每个变量定义不同的迭代过程。尽管可以使用多个变量,但你只能在for 循环中定义一种条件。
#!/bin/bash
# multiple variables
for (( a=1, b=10; a <= 10; a++, b-- ))
do
echo "$a - $b"
done
while 命令
while 的基本格式是:
while test command
do
other commands
done
比如:
#!/bin/bash
var1=10
while [ $var1 -gt 0 ]
do
echo $var1
var1=$[ $var1 - 1 ]
done
我们也可以使用多个测试条件:
$ cat test11
#!/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 语句中,在每次迭代中所有的测试命令都会被执行,包括测试命令失败的最后一次迭代。要留心这种用法。另一处要留意的是该如何指定多个测试命令。注意,每个测试命令都出现在单独的一行上。
until 命令
until 命令的格式如下:
until test commands
do
other commands
done
和 while 命令类似, until 命令中可以放入多个测试命令。只有最后一个命令的退出状态码决定了 bash shell 是否执行已定义的 other commands。
$ cat test18
#!/bin/bash
var1=5
until [ $var1 -eq 1 ]
[ $var1 -eq 0 ]
do
echo $var1
var1=$[ $var1 - 1 ]
done
$ /bin/bash file18
5
4
3
2
1
嵌套循环
循环语句可以在循环内使用任意类型的命令,包括其他循环命令。比如:
#!/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
循环处理文件
我们可以利用嵌套循环提取文件每一行的每个字段:
#!/bin/bash
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
得到的输出类似于:
Values in rich:x:501:501:Rich Blum:/home/rich:/bin/bash -
rich
x
501
501
Rich Blum
/home/rich
/bin/bash
控制循环
我们可以通过 continue
或 break
来跳过当次或整个循环(和 C/C++/Python/Java 一样)
处理循环的输出
我们可以对循环的输出使用管道或进行重定向,只需要在 done
后面添加重定向符号即可。
for file in /home/pi/*
do
if [ -d "$file" ]
then
echo "$file is a directory"
elif
echo "$file is a file"
fi
done > output.txt