Shell 字段分隔符与迭代器,内部字段分隔符(Internal Field Separator,IFS)是shell脚本编程中的一个重要概念。在处理文本数据时,它的作用可不小。
作为分隔符,IFS有其特殊用途。它是一个环境变量,其中保存了用于分隔的字符。它是当前shell环境使用的默认定界字符串。
考虑一种情形:我们需要迭代一个字符串或逗号分隔型数值(Comma Separated Value,CSV)中的单词。如果是前者,可以使用IFS=" "
;如果是后者,则使用IFS=","
。
预备知识
考虑CSV数据的情况:
data="name, gender,rollno,location"
我们可以使用IFS读取变量中的每一个条目。
oldIFS=IFS
IFS=, #IFS现在被设置为,
for item indata;
do
echo Item: item
done
IFS=oldIFS
输出如下:
Item: name
Item: gender
Item: rollno
Item: location
IFS的默认值为空白字符(换行符、制表符或者空格)。
当IFS被设置为逗号时,shell将逗号视为一个定界符,因此变量$item
在每次迭代中读取由逗号分隔的子串作为变量值。
如果没有把IFS设置成逗号,那么上面的脚本会将全部数据作为单个字符串打印出来。
实战演练
让我们以/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 inline;
do
[ count -eq 0 ] && user=item;
[ count -eq 6 ] && shell=item;
let count++
done;
IFS=oldIFS
echouser's shell is $shell;
输出为:
root's shell is /bin/bash
循环在对一系列值进行迭代时非常有用。Bash提供了多种类型的循环。
- 面向列表的
for
循环
for var in list;
do
commands; #使用变量$var
done
list可以是一个字符串,也可以是一个值序列。
我们可以使用echo
命令生成各种值序列:
echo {1..50}; #生成一个从1~50的数字序列
echo {a..z} {A..Z}; #生成大小写字母序列
同样,我们可以将这些方法结合起来对数据进行拼接(concatenate)。下面的代码中,变量i
在每次迭代的过程里都会保存一个范围在a到z之间的字符:
for i in {a..z}; do actions; done;
- 迭代指定范围的数字
for((i=0;i<10;i++))
{
commands; #使用变量$i
}
- 循环到条件满足为止
当条件为真时,while循环继续执行;当条件不为真时,until循环继续执行。
while condition
do
commands;
done
用true
作为循环条件能够产生无限循环。
until
循环在Bash中还可以使用一个特殊的循环until
。它会一直循环,直到给定的条件为真。例如:
x=0;
until [ x -eq 9 ]; #条件是[x -eq 9 ]
do
let x++; echo $x;
done