Bash,从文件中逐行读取,使用IFS分隔符。

15

我正在使用来自http://bash.cyberciti.biz/guide/While_loop的代码,用于逐行读取文件。

file=/etc/resolv.conf
while IFS= read -r line
do
        # echo line is stored in $line
    echo $line
done < "$file"

我不明白的部分是 IFS= 以及它如何对此功能有所贡献。 有人能向我解释一下吗?谢谢。


请查看在 [unix.SE] 上的 等效问题 - Stephane Chazelas
4个回答

44
在这种情况下,IFS被设置为空字符串,以防止read从行中剥离前导和尾随空格。
通常更改IFS是为了控制输入将如何拆分成多个字段。但在这种情况下,由于read只给出了一个变量名,无论IFS的值如何,read都不会将输入拆分成多个字段。但是,它将删除前导和尾随空白符,根据POSIX规范(假设IFS的值包含空格或未设置)。
有关其工作原理的详细信息,请参见POSIX规范中的read字段拆分

4
在该页面的第三个示例中,将IFS设置为null可以防止单词拆分,这使得该代码无法工作。以下是该代码:
while IFS= read -r field1 field2 field3 ... fieldN
do
    command1 on $field1
    command2 on $field1 and $field3
    ..
    ....
    commandN on $field1 ... $fieldN
done < "/path/to dir/file name with space"

如原文所述,该行中的所有单词都存储在field1中,而field2等为空。将该行更改为以下内容即可正常工作:
while read -r field1 field2 field3 ... fieldN

-3

要将IFS设置为真正的行分隔符,请使用IFS=$'\012'


2
你没有回答问题。问题是解释命令中的IFS=部分,以及它的用途。顺便说一句,IFS=$'\n'可能会更清晰(尽管有争议)。 - gniourf_gniourf
非常正确。但是这部分基本上已经在上面得到了回答,这些都是细节问题。也许这个问题应该被视为已经得到了回答。 - user3673660
如果问题已经得到回答,那么添加与问题无关的答案就没有意义了。噢,这是你的选择;也许你甚至会因此获得赞同。或者不会。等着瞧吧。 - gniourf_gniourf

-4

IFS 是一种用于行分隔符(实际上是“内部字段分隔符”)的变量。该代码将有效地清空您的读取命令的行分隔符并将其设置为默认值。有时,由于用户希望使用其他“行”结束方式(例如逐句阅读IFS=.),因此在代码的其他位置更改 IFS。

我想他们在这里包含了 IFS= 只是为了确保它适用于每个人,而不管 IFS 变量的先前值如何。即使没有 IFS=,该代码仍应正常工作。


没错,没有 IFS= 也能正常工作。非常感谢。 - wakandan
只有一个快速的问题,我们可以将这样的赋值IFS=read -r line放在同一行吗?这是允许的吗? - wakandan
2
user121870,是的,这是允许的。当在命令前面放置变量时,该变量仅对该命令可见。这适用于所有Bash命令,即使是您自己在终端中编写的命令也是如此。例如,请尝试执行此命令:“MANWIDTH=20 man bash”。 - Emil Vikström
1
IFS设置为空并不会将其设置为默认值(默认值为空格、制表符、换行符)。它不仅用于行结尾,还用于进行单词分割。要逐句阅读,可以使用read命令的-d定界符选项。 - Dennis Williamson
15
这个答案是不正确的——将IFS设置为空字符串是为了防止read从每行中删除前导和尾随空格。 - Richard Hansen
5
IFS并不是行分隔符,而是字段分隔符。这意味着它用于在行内和行间进行分隔。但在这种情况下,因为您正在使用一个输出变量的read函数,它是有效的。例如,如果您想更快地解析/etc/resolv.conf文件,可以使用while IFS=' ' read -r name address来同时拆分字段。 - l0b0

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接