**内部字段分隔符(Internal Field Separator,IFS)**是shell脚本中的一个重要概念。在处理文本数据时,它可是相当有用。我们将会讨论把单个数据流划分成不同数据元素的定界符。内部字段分隔符是用于特定用途的定界符。IFS是存储定界符的环境变量。它是当前shell环境使用的默认定界字符串。

考虑一种情形:我们需要迭代一个字符串或**CSV(Comma Separated Value,逗号分隔型数值)**中的单词。在前者中,我们使用IFS=".";在后者中,则使用IFS=","。让我们看看应该怎么做。

1. 预备知识

考虑CSV数据的情况:

data="name,sex,rollno,location" 
#我们可以使用IFS读取变量中的每一个条目
oldIFS=$IFS
IFS=, #将IFS设置为逗号
for item in $data;
do
echo Item: $item
done

IFS=$oldIFS

输出如下:

Item: name
Item: sex
Item: rollno
Item: location

IFS的默认值为空白字符(换行符、制表符或者空格)。

当IFS被设置为逗号时,shell将逗号解释成一个定界符,因此变量 $item在每次迭代中读取由逗号分隔的字串作为变量值。

如果没有把IFS设置成",",那么上面的脚本会将全部数据作为单个字符串打印出来。

2. 实战演练

让我们以 /etc/passwd为例,看看IFS的另一种用法。在文件 /etc/passwd中,每一行包含了由冒号划分的多个条目。文件中的每行都对应一位用户的相关属性。

考虑这样的输入:root:x:0:0:root:/root:/bin/bash。每行的最后一项指定了用户的默认shell。可以按照下面的方法巧妙地利用IFS打印出用户以及他们默认的shell:

#!/bin/bash
#用途: 演示IFS的用法
line="root:x:0:0:root:/root:/bin/bash"
oldIFS=$IFS;
IFS=":"
count=0
for item in $line;
do

[ $count -eq 0 ] && user=$item;
[ $count -eq 6 ] && shell=$item;
let count++
done;
IFS=$oldIFS
echo $user\'s shell is $shell;

输出为:

root's shell is /bin/bash

对一系列值进行迭代的时候,循环非常有用。Bash提供了多种类型的循环。下面就来看看怎么样使用它们。

for循环

for var in list; 
do
commands; # 使用变量$var
done
list can be a string, or a sequence.

我们可以轻松地生成不同的序列。

echo {1..50}能够生成一个从1到50的数字列表。

echo {a..z}{A..Z},或是使用{a..h}生成部分列表。类似地,将这些方法结合起来,我们就可以连接(concatenate)数据。

下面的代码中,变量i在每次迭代的过程里都会保存一个字符,范围从az

for i in {a..z}; do actions; done;

for循环也可以采用C语言中for循环的格式。例如:

for((i=0;i<10;i++))
{
commands; # 使用变量$i
}

while循环

while condition
do
commands;
done

true作为循环条件能够产生无限循环。

until循环

在Bash中还可以使用一个特殊的循环until。它会一直执行循环直到给定的条件为真。例如:

x=0;
until [ $x -eq 9 ]; # [ $x -eq 9 ] is the condition
do let x++; echo $x;
done