for命令

bash shell提供了for命令,允许你创建一个遍历一系列值的循环。每次迭代都使用其中一个值来执行已定义好的一组命令。下面是bash shell中for命令的基本格式。

for var in list 
do
commands
done 

在list参数中,你需要提供迭代中要用到的一系列值。可以通过几种不同的方法指定列表中的值。

读取列表中的值

for命令最基本的用法就是遍历for命令自身所定义的一系列值。

有时会遇到难处理的数据。shell看到了列表值中的单引号并尝试使用它们来定义一个单独的数据值.

for test in I don't know if this'll work

有两种办法可解决这个问题:

  1. 使用转义字符(反斜线)来将单引号转义;
  2. 使用双引号来定义用到单引号的值。

解决如下:

for test in I don\'t know if "this'll" work

另外要注意的是,在某个值两边使用双引号时,shell 并不会将双引号当成值的一部分。

for循环假定每个值都是用空格分割的。如果在单独的数据值中有 空格,就必须用双引号将这些值圈起来。

从变量读取列表

通常shell脚本遇到的情况是,你将一系列值都集中存储在了一个变量中,然后需要遍历变量中的整个列表。也可以通过for命令完成这个任务。

list="Alabama Alaska Arizona Arkansas Colorado"
list=$list" Connecticut"
for state in $list

$list变量包含了用于迭代的标准文本值列表。注意,代码还是用了另一个赋值语句向$list 变量包含的已有列表中添加(或者说是拼接)了一个值。这是向变量中存储的已有文本字符串尾 部添加文本的一个常用方法。

从命令读取值

生成列表中所需值的另外一个途径就是使用命令的输出。可以用命令替换来执行任何能产生输出的命令,然后在for命令中使用该命令的输出。

for state in $(cat $file)

更改字段分隔符

特殊的环境变量IFS,叫作内部字段分隔符(internal field separator)。 IFS环境变量定义了bash shell用作字段分隔符的一系列字符。默认情况下,bash shell会将下列字 符当作字段分隔符:

  1. 空格
  2. 制表符
  3. 换行符

如果bash shell在数据中看到了这些字符中的任意一个,它就会假定这表明了列表中一个新数据字段的开始。在处理可能含有空格的数据(比如文件名)时,这会非常麻烦.

要解决这个问题,可以在shell脚本中临时更改IFS环境变量的值来限制被bash shell当作字段 分隔符的字符。例如,如果你想修改IFS的值,使其只能识别换行符,那就必须这么做:

 IFS=$'\n'

将这个语句加入到脚本中,告诉bash shell在数据值中忽略空格和制表符。

如果要指定多个IFS字符,只要将它们在赋值行串起来就行。

IFS=$'\n':;"

这个赋值会将换行符、冒号、分号和双引号作为字段分隔符。如何使用IFS字符解析数据没有任何限制。

在处理代码量较大的脚本时,可能在一个地方需要修改IFS的值,然后忽略这次修改,在脚本的其他地方继续沿用IFS的默认值。一个可参考的安全实践是在改变IFS之前保存原来的IFS值,之后再恢复它。

这种技术可以这样实现:

IFS.OLD=$IFS 
IFS=$'\n' 
<在代码中使用新的IFS值> 
IFS=$IFS.OLD

这就保证了在脚本的后续操作中使用的是IFS的默认值。

用通配符读取目录

可以用for命令来自动遍历目录中的文件。进行此操作时,必须在文件名或路径名中 使用通配符。它会强制shell使用文件扩展匹配。文件扩展匹配是生成匹配指定通配符的文件名或 路径名的过程。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
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命令中列出多个目录通配符,将目录查找和列表合并进同一个for语句。

for file in /home/rich/.b* /home/rich/badtest

for语句首先使用了文件扩展匹配来遍历通配符生成的文件列表,然后它会遍历列表中的下 一个文件。可以将任意多的通配符放进列表中。

C 语言风格的 for 命令

bash shell也支持一种for循环,它看起来跟C语言风格的for循环类似,但有一些细微的不同,其中包括一些让shell脚本程序员困惑的东西。以下是bash中C语言风格的for循环的基本格式。

for (( variable assignment ; condition ; iteration process ))

C语言风格的for循环的格式会让bash shell脚本程序员摸不着头脑,因为它使用了C语言风格 的变量引用方式而不是shell风格的变量引用方式。C语言风格的for命令看起来如下。

for (( a = 1; a < 10; a++ )) 注意,有些部分并没有遵循bash shell标准的for命令:

  1. 变量赋值可以有空格;
  2. 条件中的变量不以美元符开头;
  3. 迭代过程的算式未用expr命令格式。

例子如下:

for (( i=1; i <= 10; i++ ))
do
    echo "The next number is $i"
done

C语言风格的for命令也允许为迭代使用多个变量。

for (( a=1, b=10; a <= 10; a++, b-- ))