我想这里的每个人都熟悉这句谚语,即所有文本文件都应该以换行符结尾。我已经知道这个“规则”很多年了,但我一直在想——为什么?


当前回答

基本上,如果没有得到最终EOL EOF,许多程序将无法正确处理文件。

GCC警告您这一点,因为它是C标准的一部分。(第5.1.1.2节明显)

“文件末尾没有换行符”编译器警告

其他回答

基本上,如果没有得到最终EOL EOF,许多程序将无法正确处理文件。

GCC警告您这一点,因为它是C标准的一部分。(第5.1.1.2节明显)

“文件末尾没有换行符”编译器警告

因为POSIX标准就是这样定义一行的:

3.206线路一个由零个或多个非<换行符>字符加上一个终止<换行符]字符组成的序列。

因此,不以换行符结尾的行不被视为实际行。这就是为什么有些程序在处理文件的最后一行时遇到问题,如果它不是换行符。

在使用终端仿真器时,该指南至少有一个硬优势:所有Unix工具都希望使用此约定并使用它。例如,当使用cat连接文件时,以换行符结尾的文件将具有不同于不使用的效果:

$ more a.txt
foo
$ more b.txt
bar$ more c.txt
baz
$ cat {a,b,c}.txt
foo
barbaz

而且,如前一个示例所示,当在命令行上显示文件时(例如,通过more),换行的文件会导致正确的显示。未正确终止的文件可能会乱码(第二行)。

为了保持一致性,遵循这一规则非常有帮助——否则在处理默认Unix工具时会产生额外的工作。


换一种方式思考:如果行没有以换行符结尾,那么让cat之类的命令变得有用就要困难得多了:如何创建一个连接文件的命令,以便

它将每个文件的开头放在一个新行上,这是您95%的时间所希望的;但是它允许合并两个文件的最后一行和第一行,就像上面的例子中的b.txt和c.txt?

当然,这是可以解决的,但您需要使cat的使用更加复杂(通过添加位置命令行参数,例如cat a.txt--no newline b.txt c.txt),现在命令而不是每个单独的文件控制它如何与其他文件粘贴在一起。这几乎肯定不方便。

……或者您需要引入一个特殊的哨兵字符来标记应该继续而不是终止的行。好吧,现在您遇到了与POSIX相同的情况,除了反转(行继续而不是行终止字符)。


现在,在非POSIX兼容的系统(现在主要是Windows)上,问题是没有意义的:文件通常不会以换行符结尾,例如,行的(非正式)定义可能是“用换行符分隔的文本”(注意重点)。这是完全有效的。然而,对于结构化数据(例如编程代码),它使解析更加复杂:这通常意味着必须重写解析器。如果解析器最初是在考虑POSIX定义的情况下编写的,那么修改令牌流可能比修改解析器更容易——换句话说,在输入末尾添加一个“人造换行符”令牌。

一个单独的用例:当文本文件受版本控制时,提交卫生。

如果将内容添加到文件末尾,则先前是最后一行的行将被编辑为包含换行符。这意味着,打开文件以了解该行最后一次编辑的时间将显示换行符添加,而不是您实际希望看到的提交。

(该示例特定于git,但同样的方法也适用于其他版本控制系统。)

有些工具会这样做。例如,wc期望如下:

$ echo -n "Line not ending in a new line" | wc -l
0
$ echo "Line ending with a new line" | wc -l
1

为什么文本文件应该以换行符结尾?

因为这是最明智的选择。

获取包含以下内容的文件:,

one\n
two\n
three

其中,\n表示换行符,在Windows上是返回字符,\r\n后跟换行符,因为它很酷,对吗?

这个文件有多少行?Windows说3,我们说3,POSIX(Linux)说文件是残缺的,因为文件末尾应该有一个。

无论如何,你会说它的最后一行是什么?我想任何人都同意三行是文件的最后一行,但POSIX表示这是一个残缺的行。

第二行是什么?哦,这里有第一个强烈的分离:

Windows说两个是因为文件是“用换行符分隔的行”(wth?);POSIX说2,并补充说这是一条真实、诚实的路线。

那么,选择Windows的后果是什么?简单:

你不能说文件是由行组成的

为什么?尝试从上一个文件中取出最后一行并复制几次。。。你得到了什么?这:

one\n
two\n
threethreethreethree

相反,尝试交换第二行和第三行。。。你会发现:

one\n
threetwo\n

因此

您必须说,文本文件是行和\n的交替,以行开始,以行结束

这真是一口,对吧?

你想要另一个奇怪的结果?

你必须接受一个空文件(0字节,实际上是0位)是一个单行文件,神奇的是,因为它们在微软很酷

这真是太疯狂了,你不觉得吗?

POSIX选择的后果是什么?

顶部的文件有点残缺,我们需要一些黑客来处理它。

是认真的

在前面的文本中,我是挑衅性的,因为处理缺少结尾的文本文件会迫使您使用特殊的滴答声/黑客来处理它们。你总是需要一个if/else来让事情运转起来,其中处理残缺行的分支只处理残缺行,所有其他行都采用另一个分支。这有点种族主义,不是吗?

我的结论

我赞成POSIX对行的定义,原因如下:

文件自然被认为是一系列行一行不应该是这样或那样的,这取决于它在文件中的位置空文件不是单行文件,拜托!您不应该被迫对代码进行黑客攻击


是的,Windows确实鼓励您省略后面的\r\n。如果需要下面的两行文件,则必须省略尾部,否则文本编辑器会将其显示为三行文件: