01 背景写这一篇文章源于在工作遇到了一个比较有趣的问题,我在写shell脚本的时候,发现echo的结果和预期不一致。具体如下:
我有一个文件,文件中有两列,假设文件test.txt内容如下:

a 1
b 2
c 3
d 4


此时我想通过循环,将每一列的值显示出来

for line in `cat test.txt`; do echo $line ;done


预期的结果是:

a 1
b 2
c 3
d 4


实际的结果是:

你可能不知道的Bash脚本中IFS变量的含义和使用方法!_字段


我尝试过将变量使用双引号引起来,但显示还是这样:

你可能不知道的Bash脚本中IFS变量的含义和使用方法!_换行符_02


使用echo -n 不还换行?显示如下:

你可能不知道的Bash脚本中IFS变量的含义和使用方法!_分隔符_03

经过了诸多尝试都不行,很明显echo将空格作为了分隔符,并将分隔符前后的数据换行输出,那么这个分隔符是否可以自定义呢?

02 IFS的作用和含义

经过查找,发现Bash IFS变量是干这个事的,先来一波来自百度的介绍:

在Bash Shell中,IFS(Internal Field Separator)是一个环境变量,用于指定字段分隔符。当您从命令行或文件中读取文本行时,IFS变量定义了如何将文本行拆分成字段。
IFS变量默认情况下包含空格、制表符和换行符。这意味着当您从命令行或文件中读取文本行时,默认情况下,IFS会将文本行拆分成多个字段,每个字段之间由空格、制表符或换行符分隔

即默认情况下,IFS会将文本行拆分成多个字段,每个字段之间由空格、制表符或换行符分隔。


也可使用man bash,搜索IFS,定义如下:

IFS 内部字段分隔符 Internal Field Separator 用来在扩展之后进行分词,使用内部命令 read 将行划分成词。默认值是 ``<space><tab><newline>''


可以看出IFS的默认值是一个由空格、制表符和换行符组成的三字符字符串,可通过以下命令进行验证:

[root@txy201-51 tmp]# echo "$IFS" | cat -et
 ^I$
$
[root@txy201-51 tmp]#


当我们指定只使用换行符作为分割符的时候,这个问题得以解决:

你可能不知道的Bash脚本中IFS变量的含义和使用方法!_分隔符_04


但是在默认情况下while 一个变量读取一行,如果有多个变量就以空格为分隔符:当我们存在以下文件:

John 25 65.4  
Mary 30 58.2


while只有一个变量时:

你可能不知道的Bash脚本中IFS变量的含义和使用方法!_字段_05


while有两个变量时:

你可能不知道的Bash脚本中IFS变量的含义和使用方法!_分隔符_06


while有三个变量时:

你可能不知道的Bash脚本中IFS变量的含义和使用方法!_换行符_07


变量数量超出列时,显示空

你可能不知道的Bash脚本中IFS变量的含义和使用方法!_字段_08


总之,我们可以巧妙地利用IFS参数,编写更为简洁的脚本,如在while中指定IFS的方式:

你可能不知道的Bash脚本中IFS变量的含义和使用方法!_字段_09