shell中的IFS
变量IFS在shell中被用作输入字段分隔符(input field separator)或内部字段分隔符(internal field separator)。
本质上,它是一个由特殊字符组成的字符串,在分割行输入时用来作为单词/字段之间的分隔符。
IFS的默认值是空格(ASCII编码0x20)、制表符(ASCII编码0x09,一般表示为'\t')、换行符(ASCII编码为0x0A,一般表示为'\n')。
如果未设置IFS,其使用默认值。
如果IFS被设置为空字符串(这与未设置IFS不同),则不会进行切分。
#IFS使用默认值,正常进行分割
[root@k8s-node-4 sh_learn]# read -r a b c <<< 'the plain gold ring'
[root@k8s-node-4 sh_learn]# echo "<$a>"
<the>
[root@k8s-node-4 sh_learn]# echo "<$b>"
<plain>
[root@k8s-node-4 sh_learn]# echo "<$c>"
<gold ring>#为IFS设置空值,不进行切分
[root@k8s-node-4 sh_learn]# IFS= read -r a b c <<< 'the plain gold ring'
[root@k8s-node-4 sh_learn]# echo "<$a>"
<the plain gold ring>
[root@k8s-node-4 sh_learn]# echo "<$b>"
<>
[root@k8s-node-4 sh_learn]# echo "<$c>"
<>
此变量被用于多个不同地方,语义略有不同:
- 在read命令中,如果指定了多个变量名称参数,IFS被用来分割输入行,使得每个变量都被赋予输入行中的单个字段值。(如果字段的数量比变量多,则最后一个变量被赋予所有剩余字段值)。
注意:当将多余的字段赋予最后一个变量时,不会对剩余部分的字符串进行分割和空白压缩。
#下面的示例中,字段数量比变量多,会将剩余部分都赋值给最后一个变量c,但不进行分割和空白压缩。
[root@k8s-node-4 sh_learn]# IFS=$' \t\n' read -r a b c <<< 'the plain gold ring'
[root@k8s-node-4 sh_learn]# echo "<$a> <$b> <$c>"
<the> <plain> <gold ring>#下面的示例中,2后面有3个冒号,第一个冒号被用来分割字段,所以变量c的值以两个冒号开始。
[root@k8s-node-4 sh_learn]# IFS=: read -r a b c <<< '1:2:::3::4'
[root@k8s-node-4 sh_learn]# echo "<$a> <$b> <$c>"
<1> <2> <::3::4>
-
在read命令中,IFS中的任何空白字符,若出现在输入行的首尾位置,都将被删除,即使仅有一个变量。
#在下面的示例中,字符串awd前后的空白字符都被删除,变量a的值是awd。 [root@k8s-node-4 sh_learn]# read -r a <<< " awd " [root@k8s-node-4 sh_learn]# echo "<$a>" <awd>
在字段分割场景下,针对IFS中的空白字符时,有特殊的处理规则。字符串前后出现的IFS中的空白字符会被删除,字符串内部的连续空白字符会被当做单个分隔符。
#对IFS中空白字符的特殊处理。输入字符串以多个空格开始,字段之间也有多个空格。按照上述规则处理后,变量获取了正确的值。
[root@k8s-node-4 sh_learn]# IFS=$' \t\n' read -r one two three \
> <<< ' 1 2 3'
[root@k8s-node-4 sh_learn]# echo $one
1
[root@k8s-node-4 sh_learn]# echo $two
2
[root@k8s-node-4 sh_learn]# echo $three
3#针对非空白字符,不会被删除和压缩。可以看到,输入中两个连续的冒号都被当做分隔符,所以变量gecos的值是空的
[root@k8s-node-4 sh_learn]# IFS=: read -r user pwhash uid gid gecos home shell <<< 'statd:x:105:65534::/var/lib/nfs:/bin/false'
[root@k8s-node-4 sh_learn]# echo "<$user>" "<$pwhash>" "<$uid>" "<$gid>" "<$gecos>" "<$home>" "<$shell>"
<statd> <x> <105> <65534> <> </var/lib/nfs> </bin/false>
如果IFS中同时包含空白字符和非空白字符,则处理方式如下:
- 任何非空白字符及该字符相邻的所有空白字符都被当做单个字段分隔符;
- 单个空白字符或非空白字符也会被当做字段分隔符;
#在下面的示例中,将IFS的值设置为空格和逗号,则单个空格(four和five之间),单个逗号(one和two之间),逗号以及相邻的所有空格(two和three之间,three和four之间),都被当做分隔符。
[root@k8s-node-4 sh_learn]# IFS=' ,'
[root@k8s-node-4 sh_learn]# var='one,two, three , four five'
[root@k8s-node-4 sh_learn]# printf "<%s>\n" $var
<one>
<two>
<three>
<four>
<five>