作者:jicanmeng
时间:2016年05月13日
for命令的格式如下:
for var in list
do
commands
done
一般情况下,list中的各项使用空格分开。每项都赋值给var变量。如果list中的项包含空格,我们可以用转义字符对空格进行转义,或用双引号或单引号。举例如下:
[jicanmeng@andy tmp]$ cat 1-for.sh
#!/bin/bash
for city in beijing shanghai shenzhen
do
echo "visit beautiful $city"
done
for city in bei\ jing "shang hai" 'shen zhen'
do
echo "Visit beautiful $city"
done
[jicanmeng@andy tmp]$ bash 1-for.sh
visit beautiful beijing
visit beautiful shanghai
visit beautiful shenzhen
Visit beautiful bei jing
Visit beautiful shang hai
Visit beautiful shen zhen
[jicanmeng@andy tmp]$
list的内容也可以通过读取文件来获得。例如下面的例子:
[jicanmeng@andy tmp]$ cat city.txt
bei jing
shang hai
shen zhen
[jicanmeng@andy tmp]$ cat 2-for.sh
#!/bin/bash
for city in `cat city.txt`
do
echo "visit beautiful $city"
done
[jicanmeng@andy tmp]$ bash 2-for.sh
visit beautiful bei
visit beautiful jing
visit beautiful shang
visit beautiful hai
visit beautiful shen
visit beautiful zhen
[jicanmeng@andy tmp]$
这和我们期望的不一样。我们期望一行一行打印,而实际结果是一行中的空格也作为了分隔符,分隔符前后的内容分别赋值给了city。这个问题的原因是一个特殊的环境变量IFS,称为内部字段分隔符(internal filed separator)。IFS环境变量保存了bash shell用作字段分隔符的一系列字符。默认情况下,bash shell会将下列字符当作字段分隔符:
如果bash shell在数据列表中看到了这些字符中的任意一个,它会假定你在数据列表中开始了一个新的数据段。在读取文件时,如果文件中包含空格,可能就会比较麻烦,例如上面的例子。
要解决这个问题,我们可以在shell脚本中临时更改一些IFS环境变量的值,处理完数据后再把IFS的原值更改回来。例如下面的例子:
[jicanmeng@andy tmp]$ cat city.txt
bei jing
shang hai
shen zhen
[jicanmeng@andy tmp]$ cat 3-for.sh
#!/bin/bash
IFSOLD=$IFS
IFS=$'\n'
for city in `cat city.txt`
do
echo "visit beautiful $city"
done
IFS=$IFSOLD
[jicanmeng@andy tmp]$ bash 3-for.sh
visit beautiful bei jing
visit beautiful shang hai
visit beautiful shen zhen
[jicanmeng@andy tmp]$
IFS=$'\n'
表示IFS环境变量中只包含换行符。
如果你要指定多个IFS字符,只要将它们在赋值行串起来就行。例如IFS=$'\n:;"'
这个赋值语句会将换行符、冒号、分号和双引号作为字段分隔符。
for命令在一种情况下也非常常见。那就是遍历一个目录下面的所有文件的目录和文件名称。例如:
[jicanmeng@andy tmp]$ cat 4-for.sh
#!/bin/bash
for file in /home/jicanmeng/*
do
if [ -d "$file" ]
then
echo "$file is a directory"
elif [ -f "$file" ]
then
echo "$file is a file"
fi
done
[jicanmeng@andy tmp]$ bash 4-for.sh
/home/jicanmeng/2015年年终总结.txt is a file
/home/jicanmeng/Downloads is a directory
/home/jicanmeng/lib is a directory
/home/jicanmeng/pictures is a directory
/home/jicanmeng/Public is a directory
/home/jicanmeng/softwares is a directory
/home/jicanmeng/VirtualBox VMs is a directory
/home/jicanmeng/work is a directory
[jicanmeng@andy tmp]$
这里要提醒一下,测试文件是文件还是目录的时候,注意添加双引号。如果不这么做,那么遇到包含有空格的目录或文件名时会提示参数过多的错误。
bash shell也支持另一种形式的for循环,看起来和c语言风格的for循环非常类似。格式如下:
for (( variable assignment; condition; iteration process ))
注意,有一些事情没有遵循标准的bash shell的for命令:1. 给变量赋值等号前后可以有空格; 2. 条件中的变量不以$开头; 3. 迭代过程的算式未用expr命令格式。举例如下:
[jicanmeng@andy tmp]$ cat 5-for.sh
#!/bin/bash
for (( i = 1; i < 5; i++ ))
do
echo "The next number is $i"
done
for (( a=1,b=5; a<5; a++,b-- ))
do
echo "$a - $b"
done
[jicanmeng@andy tmp]$ bash 5-for.sh
The next number is 1
The next number is 2
The next number is 3
The next number is 4
1 - 5
2 - 4
3 - 3
4 - 2
[jicanmeng@andy tmp]$
while命令的基本格式:
while command
do
commands
done
两点需要注意:
;
或&&
连接起来。特别注意的是,while的条件是否满足,取决于while命令中的最后一条命令的退出状态码。
[jicanmeng@andy tmp]$ cat 6-while.sh
#!/bin/bash
var1=3
while [ $var1 -gt 0 ]
do
echo $var1
var1=$[ var1 -1 ]
done
echo "first while end"
var1=3
while echo $var1
test $var1 -ge 0
do
echo "This is inside the loop"
var1=$[$var1-1]
done
echo "second while end"
var1=3
while test $var1 -ge 0 && echo $var1
do
echo "This is inside the loop"
var1=$[$var1-1]
done
[jicanmeng@andy tmp]$ bash 6-while.sh
3
2
1
first while end
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
second while end
3
This is inside the loop
2
This is inside the loop
1
This is inside the loop
0
This is inside the loop
[jicanmeng@andy tmp]$
until命令的基本格式:
until command
do
commands
done
until命令和while命令的格式和参数完全相同,只有一点需要注意:while后面的命令退出状态码为0时,才会执行do后面的命令;而until后面的命令退出码不为0时,才会执行do后面的命令。
和c语言一样,bash shell也支持在循环中使用break命令和continue命令。它们都可以加一个参数:break n
。默认情况下,n为1;如果你将n设为2,break就会停止上一级的外部循环。这在嵌套循环中非常有用。举例如下:
[jicanmeng@andy tmp]$ cat 7-break.sh
#!/bin/bash
for a in 1 2 3 4
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
[jicanmeng@andy tmp]$ bash 7-break.sh
outer loop: 1
inner loop: 1
inner loop: 2
inner loop: 3
inner loop: 4
[jicanmeng@andy tmp]$
无论是使用for,还是使用while,还是使用until,都可以在done后面加上重定向符号,将循环的输出重定向到文件中。或在done后面添加管道符号|,将循环的输出传递给另外一个程序。举例如下:
[jicanmeng@andy tmp]$ cat 8-redirection.sh
#!/bin/bash
for file in /home/jicanmeng/*
do
if [ -d "$file" ]
then
echo "$file is a directory"
elif [ -f "$file" ]
then
echo "$file is a file"
fi
done > output.txt
[jicanmeng@andy tmp]$ bash 8-redirection.sh
[jicanmeng@andy tmp]$ cat output.txt
/home/jicanmeng/2015年年终总结.txt is a file
/home/jicanmeng/Downloads is a directory
/home/jicanmeng/lib is a directory
/home/jicanmeng/pictures is a directory
/home/jicanmeng/Public is a directory
/home/jicanmeng/softwares is a directory
/home/jicanmeng/VirtualBox VMs is a directory
/home/jicanmeng/work is a directory
[jicanmeng@andy tmp]$
[jicanmeng@andy tmp]$ cat 9-example.sh
#!/bin/bash
IFSOLD=$IFS
IFS=$'\n'
for line in `cat /etc/passwd`
do
echo "values in $line -"
IFS=:
for column in $line
do
echo " $column"
done
done
[jicanmeng@andy tmp]$ bash 9-example
[jicanmeng@andy tmp]$ cat output.txt
values in root:x:0:0:root:/root:/bin/bash -
root
x
0
0
root
/root
/bin/bash
...
[jicanmeng@andy tmp]$