我想这里的每个人都熟悉这句谚语,即所有文本文件都应该以换行符结尾。我已经知道这个“规则”很多年了,但我一直在想——为什么?
当前回答
因为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定义的情况下编写的,那么修改令牌流可能比修改解析器更容易——换句话说,在输入末尾添加一个“人造换行符”令牌。
其他回答
很可能只是一些解析代码希望它在那里。
我不确定我是否会认为这是一条“规则”,而且这肯定不是我虔诚地遵守的。最明智的代码将知道如何逐行解析文本(包括编码)(任何行结尾的选择),最后一行是否有换行符。
的确,如果你以一条新的线结束:EOL和EOF之间(理论上)是否有一条空的最终线?一个值得思考的。。。
多年来,我自己也在想这个问题。但我今天遇到了一个很好的理由。
想象一个每行都有记录的文件(例如:CSV文件)。电脑在文件末尾写记录。但它突然坠毁了。天哪,最后一行完成了吗?(情况不太好)
但是如果我们总是终止最后一行,那么我们就会知道(只需检查最后一行是否终止)。否则,为了安全起见,我们可能不得不每次都放弃最后一行。
每一行都应该以换行符结尾,包括最后一行。有些程序在处理文件的最后一行时遇到问题,如果它不是换行符。
GCC对此发出警告,并不是因为它无法处理文件,而是因为它必须作为标准的一部分。
C语言标准说非空的源文件应以换行符结尾,换行符前不得紧跟反斜杠字符。由于这是一个“应”条款,我们必须发出一条违反此规则的诊断信息。这在ANSI C 1989标准第2.1.1.2节中。ISO C 1999标准(可能还有ISO C 1990标准)第5.1.1.2节。
参考:GCC/GNU邮件存档。
基本上,如果没有得到最终EOL EOF,许多程序将无法正确处理文件。
GCC警告您这一点,因为它是C标准的一部分。(第5.1.1.2节明显)
“文件末尾没有换行符”编译器警告
我个人喜欢源代码文件末尾的新行。
它可能起源于Linux或所有UNIX系统。我记得有编译错误(如果我没弄错的话是gcc),因为源代码文件没有以空的新行结尾。为什么会这样呢。