我想这里的每个人都熟悉这样一句话:所有文本文件都应该以换行符结尾。我知道这个"规则"很多年了,但我一直在想——为什么?
- 只是个吹毛求疵的人。这不是文件末尾的"新行"。这是最后一行末尾的"换行符"。另外,请参阅相关问题的最佳答案:stackoverflow.com/questions/16222530/…
- 只是为了多吹毛求疵,他实际上没有写"新行",他写"新行",这是正确的。
- 不熟悉,但我想知道我是真的,因为在很多情况下,多余的新线实际上破坏了东西,这对我来说有点太高了。
- 直到今天我才听到这句格言。我知道POSIX需要它,因为很多旧工具都假设它,但是我通常生活在一个非POSIX的世界中,大多数工具都不关心这个世界。
- 我目前正在使用node.js流逐行解析纯文本数据,而缺少终端换行符是很烦人的,因为我必须为流的输入端完成/关闭时添加额外的逻辑,以确保最后一行得到处理。
- Unix在文件结尾处的一般行为方式如下所示:字符不以行开头,而是以行结尾。所以,它是一个行终止符,而不是行分隔符。第一行(和所有行一样)不需要即可开始。最后一行(与所有行一样)需要结束它。文件末尾的不会创建额外的行。然而,有时文本编辑器会在其中添加一个可见的空行。甚至Emacs也可以选择这样做。
- @我想整个混乱是口头的。为了避免这种情况,C语言和Unix开发人员可以将ascii换行符称为eol或endofrine。按照这个想法,\l将是它的自然缩写(\l在c中不使用)。然而,显然,这个小写字母l与数字"1"没有太大区别(不幸的是)。在正则表达式中使用\1。
- @好吧,是的。但你为什么现在提出这个问题?P
- @自从我提出这个是为了帮助人们。如果人们记得"行尾字符"是它的名字,他们就不会质疑为什么文件的最后一行有一个。由于开发人员抓住了下一个最好的东西(称之为"新行字符"-这是一个有点用词不当),他们自然会想,为什么它不执行其明显的功能,并在那里创建一个新行。
- @Markdblackwell我完全同意你的观点,这个名字在实际意义上有点可怕。?
- @当然,你也可以说这是在争论语义学。当然,c中的'
'是新行。但在以东十一〔四〕又有一个:以东十一〔五〕。那是换行、换行还是其他什么?那要看你问谁了。不过,我知道你在说什么:如果main()以:printf("
Test
");结尾,那么"test"下的行将是shell提示。这很微妙,但在我的脑海里仍然值得一提。(当然,putchar('
');会在提示上方显示一个空行。)
因为POSIX标准就是这样定义一行的:
- 3.206 Line
- A sequence of zero or more non- characters plus a terminating character.
因此,不以换行符结尾的行不被视为实际行。这就是为什么有些程序在处理文件的最后一行时遇到问题,如果它不是换行终止的话。
在使用终端仿真器时,这一准则至少有一个硬优势:所有的UNIX工具都期望这种约定,并使用它。例如,当将文件与cat连接时,以换行符结尾的文件与没有换行符的文件具有不同的效果:
1 2 3 4 5 6 7 8
| $ 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定义的情况下编写的,那么修改令牌流可能更容易,而不是解析器-换句话说,在输入的末尾添加一个"人工换行"标记。
- 虽然现在纠正起来相当不切实际,但显然POSIX在定义行时犯了一个错误——这是关于这个问题的问题数量的证据。一行应该被定义为以、或结尾的零个或多个字符。分析程序复杂性不是一个有效的问题。在可能的情况下,复杂性应该从程序员的头部转移到库中。
- @Dougcoburn这个答案曾经进行过详尽的技术讨论,解释了为什么这是错误的,以及为什么POSIX做了正确的事情。不幸的是,这些评论最近被一位狂热的主持人删除了。简言之,这不是解析复杂性;相反,您的定义使得以一种既有用又一致的方式编写诸如cat之类的工具变得更加困难。
- 够公平的——不幸的是他们被移走了。我有兴趣知道为什么这仍然被认为是"正确"的事情。
- @康拉德·鲁道夫,我在编辑史上什么都没看到。它不应该出现在编辑历史中吗?还是在有历史之前?早在09年…
- @形容词不是在答案中,而是在评论中。
- 哦,我明白了,"这个评论被编辑了三次。"…但你不能查看历史。
- @以前在这个答案下面有20条评论讨论这个问题。它们被删除,而不是编辑。不管怎样,我刚刚编辑了这个答案,添加了一个解释,说明为什么posix的换行定义更实用,以及如何让另一个定义看起来同样方便(doug建议的定义还不够)。
- 串联问题的解决方案是不将文件视为它们都使用相同的编码。如果我们谈论的是源代码文件,那么将它们连接起来,使第一个文件的最后一行和第二个文件的第一行合并为一行几乎没有意义。上下文很重要。试图把所有东西都擦亮,使其符合5%的用例,这几乎肯定是一个坏主意。unix和linux以前从来没有回避过命令行标志,为什么不使用a-r(对于raw)或cat之类的东西呢?我认为posix在这里犯了一个错误
- 软件应该正确处理边缘案例,而不是强制人们遵守这些愚蠢的规则(有那么多愚蠢的事情浪费了开发人员的生命)。
- @leon posix规则是关于减少边缘情况的。它做得很漂亮。事实上,我有点不知所措,人们是如何不理解这一点的:这是对一条线最简单、自我一致的定义。
- @我认为你是在假设我的一个更方便的工作流程的例子是决定背后的原因。这不是,只是一个后果。原因是POSIX规则是最简单的规则,它使在解析器中处理行变得最简单。我们进行讨论的唯一原因是Windows的做法不同,因此,有许多工具在POSIX文件上失败。如果每个人都做了POSIX,就不会有任何问题。然而,人们抱怨的是POSIX,而不是Windows。
- @如果一个文件结束了,那么最后一行当然也结束了。在我看来,这是每个人的期望。文件结束了,但您希望行继续—这很奇怪。无论如何,我不能改变sed、wc等的行为。
- @Leon您不需要更改任何这些工具的行为,当在这些工具生成的任何文件上使用它们时,或者在其他方面遵守POSIX准则时,它们的行为已经正确且一致。你如何创建一个文本文件而不是?在GNU/BSD/POSIX系统上,这已经不是小事了。
- 这与窗户无关,不要造稻草人。从字面上说,除了你,这里没有人在谈论窗户。我同意强制每个文件以新行结尾会使逐行分析变得更容易(没有意义)。我也同意这样做可以使连接文件(可能表示块而不是按行分割)更容易。我不同意的是,让解析稍微简单一点是值得的,这迫使几乎所有人在文件末尾添加一些不必要的换行符。它也没有理由编写那些没有结束换行符的文件的程序。
- @我指的只是Windows,指出POSIX规则没有意义的情况(换句话说,我在向你扔骨头)。我很高兴在这次讨论中再也不提这件事。但是,您的声明就更没有意义了:在POSIX平台上,讨论具有不同行尾约定的文本文件是没有意义的,因为没有理由生成它们。有什么优势?实际上没有。-总之,我真的不理解这个答案(或posix规则)所引起的仇恨。坦率地说,这完全是不合理的。
每行应以换行符结尾,包括最后一行。如果文件的最后一行未被换行终止,则某些程序在处理该行时遇到问题。
GCC发出警告不是因为它不能处理文件,而是因为它必须作为标准的一部分。
The C language standard says
A source file that is not empty shall end in a new-line character, which shall not be immediately preceded by a backslash character.
Since this is a"shall" clause, we must emit a diagnostic message for a violation of this rule.
This is in section 2.1.1.2 of the ANSI C 1989 standard. Section 5.1.1.2 of the ISO C 1999 standard (and probably also the ISO C 1990 standard).
参考:GCC/GNU邮件档案。
- 请编写好的程序,然后允许在处理时在需要的地方插入新行,或者能够正确处理"丢失的"程序…事实上,这是不缺失的
- @billthelizard,"如果文件的最后一行没有被换行终止,那么一些程序在处理它时有问题"的例子是什么?
- @如果文件的最后一行没有被换行终止,Pacrier wc -l将不会计算在内。另外,如果第一个文件的最后一行不是换行终止,那么cat将把文件的最后一行与下一个文件的第一行合并为一行。几乎所有寻找换行符作为分隔符的程序都有可能把这搞砸。
- @Billthelizard,我是说wc已经被提到了……
- @我不明白你的意思。
- @billthelizard,我的坏,澄清一下:如果文件的最后一行没有被换行终止,那么在处理该文件的最后一行时有问题的程序有哪些例子(除了那些在线程上已经大量提到的程序,如cat和wc)?
- 如果最后一行没有用行终止符终止,Visual Studio资源编译器(RC)将阻塞。
- @这个程序是在编译为C++ 98和C++ 03代码时调用UB的程序。参见程序:ideone.com/jswwf9
- C++ 14标准中有一点不同:"源文件不是空的,也不是以新行字符结尾的。应像在文件"[强调已添加]中附加新行字符一样进行处理。这似乎是多余的,因为翻译的第一阶段需要插入"行末指示符的新行字符"[lex.phases]。
- 我认为这个问题与海湾合作委员会无关……C标准讨论了正确的行尾文件,但从源代码的角度来看。允许编译器排列源代码字符以处理缺少最后一行结尾的文件。强制文件最后一行中的行尾(逻辑)是为了解析目的(如果文件之间没有分隔符,则可以附加两个标记)
这个答案是一个技术性的答案,而不是观点。好的。
如果我们想成为POSIX纯粹主义者,我们将一条线定义为:好的。
A sequence of zero or more non- characters plus a terminating character.
Ok.
来源:http://pubs.opengroup.org/onlinepubs/9699919799/basedefs/v1_chap03.html tag_03_206好的。
不完整的行,如:好的。
A sequence of one or more non- characters at the end of the file.
Ok.
来源:http://pubs.opengroup.org/onlinepubs/9699919799/basedefs/v1_chap03.html tag_03_195好的。
文本文件为:好的。
A file that contains characters organized into zero or more lines. The lines do not contain NUL characters and none can exceed {LINE_MAX} bytes in length, including the character. Although POSIX.1-2008 does not distinguish between text files and binary files (see the ISO C standard), many utilities only produce predictable or meaningful output when operating on text files. The standard utilities that have such restrictions always specify"text files" in their STDIN or INPUT FILES sections.
Ok.
来源:http://pubs.opengroup.org/onlinepubs/9699919799/basedefs/v1_chap03.html tag_03_397好的。
字符串为:好的。
A contiguous sequence of bytes terminated by and including the first null byte.
Ok.
来源:http://pubs.opengroup.org/onlinepubs/9699919799/basedefs/v1_chap03.html tag_03_396好的。
由此,我们可以得出,我们唯一可能遇到任何类型问题的时间是,如果我们将一个文件或一个文件的一行作为文本文件处理(即,一个文本文件是一个零行或多行的组织,并且我们知道的一行必须以一个结束)。好的。实例:wc -l filename。好的。
从wc的手册中,我们看到:好的。
A line is defined as a string of characters delimited by a character.
Ok.
JavaScript、HTML和CSS文件的含义是什么?它们是文本文件?好的。
在浏览器、现代IDE和其他前端应用程序中,在EOF中跳过EOL没有问题。应用程序将正确分析文件。因为并非所有的操作系统都符合POSIX标准,所以对于非OS工具(如浏览器)来说,根据POSIX标准(或任何OS级标准)处理文件是不切实际的。好的。
因此,我们可以相对地确信,EOF的EOL在应用程序级别几乎不会产生负面影响——无论它是否在UNIX操作系统上运行。好的。
此时,我们可以自信地说,在客户端处理JS、HTML、CSS时,在EOF跳过EOL是安全的。实际上,我们可以声明缩小这些文件中的任何一个,包含no都是安全的。好的。我们可以更进一步说,就nodejs而言,它也不能遵循POSIX标准,因为它可以在不符合POSIX的环境中运行。好的。
那我们还剩下什么?系统级工具。好的。
这意味着可能出现的唯一问题是,工具要努力使其功能符合POSIX的语义(例如,wc中所示的行的定义)。好的。
即便如此,并不是所有的shell都会自动粘附到posix上。例如,bash并不默认为posix行为。有一个开关可以启用它:POSIXLY_CORRECT。好的。
关于EOL价值的思考食物:http://www.rfc-editor.org/eolstory.txt好的。
在工具轨道上,出于所有实际目的和目的,让我们考虑一下:好的。
我们来处理一个没有EOL的文件。在编写本文时,本例中的文件是一个没有eol的小型JavaScript。好的。
1 2 3 4 5 6 7 8
| curl http://cdnjs.cloudflare.com/ajax/libs/AniJS/0.5.0/anijs-min.js -o x.js
curl http://cdnjs.cloudflare.com/ajax/libs/AniJS/0.5.0/anijs-min.js -o y.js
$ cat x.js y.js > z.js
-rw-r--r-- 1 milanadamovsky 7905 Aug 14 23:17 x.js
-rw-r--r-- 1 milanadamovsky 7905 Aug 14 23:17 y.js
-rw-r--r-- 1 milanadamovsky 15810 Aug 14 23:18 z.js |
注意,cat文件大小正好是其各个部分的总和。如果Javascript文件的串联是JS文件的问题,那么更合适的问题是用分号启动每个Javascript文件。好的。
正如这个线程中的另一个人所提到的那样:如果您希望cat两个文件的输出变成一行而不是两行,该怎么办?换句话说,cat做了它应该做的。好的。
cat的man只提到到eof时的读取输入,而不是。注意,cat的-n开关也将打印出一条非结束行(或不完整行),即计数从1开始(根据man)。好的。
-n Number the output lines, starting at 1.
Ok.
现在我们了解了posix是如何定义行的,这种行为变得模棱两可,或者说是不兼容的。好的。
了解给定工具的目的和遵从性将有助于确定使用EOL结束文件的关键性。在C、C++、Java(JAR)等中…一些标准将规定一条新的有效性线——JS、HTML、CSS不存在这样的标准。好的。
例如,如果不使用wc -l filename,可以执行awk '{x++}END{ print x}' filename,并确保任务的成功不会受到我们可能希望处理的未写入文件(例如,第三方库,如minified js we curl)的危害,除非我们的目的是真正按照posix兼容的意义计算行。好的。
结论好的。
对于某些文本文件(如JS、HTML和CSS),在EOF中跳过EOL将产生负面影响(如果有的话),这将是非常少的实际用例。如果我们依赖于的存在,那么我们只将工具的可靠性限制在我们编写的文件上,并将自己暴露在第三方文件引入的潜在错误中。好的。故事的寓意:工程师的工具,不具有依赖EOL在EOF的弱点。好的。
请随意发布应用于JS、HTML和CSS的用例,在这些用例中,我们可以检查跳过EOL是如何产生不利影响的。好的。好啊。
- RFC编辑器链接应该是rfc-editor.org/old/eolstory.txt。
- 在问题中没有标记posix…MVS/OS线路终端怎么样?还是MS-DOS行尾?顺便说一下,所有已知的POSIX系统都允许文本文件没有最后一行结尾(没有找到符合POSIX的声明系统,在内核中"文本文件"有特殊处理,以在没有它的情况下插入适当的换行符)。
- 我修复了eolstory.txt的链接,但是由于我只添加/修改了它,所以它不会让我保存它。
这可能与以下两者之间的差异有关:
- 文本文件(每行应以行结尾)
- 二进制文件(没有真正的"行",必须保留文件的长度)
如果每一行都以行尾结尾,这就避免了,例如,连接两个文本文件将使第一行的最后一行进入第二行的第一行。
另外,编辑器可以在加载时检查文件是否以行尾结尾,将其保存在本地选项"eol"中,并在写入文件时使用该选项。
几年前(2005年),许多编辑(zde,eclipse,scite,…)确实"忘记"了最后的EOL,这并不是很受欢迎。不仅如此,他们还错误地将最终的EOL解释为"开始新行",并实际开始显示另一行,就好像它已经存在一样。与在上面的某个编辑器中打开文本文件相比,使用"正确的"文本文件和像Vim这样的行为良好的文本编辑器,这是非常明显的。它在文件的实际最后一行下面显示了一行多余的内容。你看到这样的东西:
1 2 3 4
| 1 first line
2 middle line
3 last line
4 |
- + 1。我在遇到这个问题时发现了这个问题。Eclipse将最后一行显示为"假"是非常恼人的,如果我删除它,那么Git(以及所有其他需要eol的Unix工具)会抱怨。另外,请注意,这不仅是在2005年:Eclipse4.2Juno仍然存在这个问题。
- @mestrelion,请继续访问stackoverflow.com/questions/729692/…
一些工具对此有所期待。例如,wc预计:
1 2 3 4
| $ echo -n"Line not ending in a new line" | wc -l
0
$ echo"Line ending with a new line" | wc -l
1 |
- 我不会说"一些",我说大多数工具都希望文本文件,如果不是全部。cat、git、diff、wc、grep、sed…名单很大
- 也许有人会说,wc并不期望这样,因为它只是在"线"的posix定义中工作,而不是大多数人对"线"的直观理解。
- @Guildenstern直观的定义是,在这两种情况下,wc -l打印1,但有些人可能会说第二种情况应该打印2。
- @flimm如果你把
看作一个行终止符,而不是像posix/unix那样的行分隔符,那么期待第二个案例打印2就完全是疯了。
基本上,有许多程序如果不能得到最终的EOL EOF,就不能正确地处理文件。
GCC警告您这一点,因为它是C标准的一部分。(第5.1.1.2节显然)
"文件结尾没有换行"编译器警告
- GCC并不能处理文件,它必须作为C标准的一部分给出警告。
- 好点,用适当的部分更新)
- IIRC,MSVC 2005抱怨C文件以不完整的行结尾,可能拒绝编译它们。
这源于早期使用简单终端的时代。换行符用于触发传输数据的"刷新"。
今天,不再需要换行符了。当然,如果新线不在的话,很多应用程序仍然存在问题,但我认为这是这些应用程序中的一个缺陷。
但是,如果您有一个需要换行的文本文件格式,那么您可以得到非常便宜的简单数据验证:如果文件以一个末尾没有换行的行结尾,那么您就知道该文件被破坏了。每行只有一个额外的字节,您可以高精度地检测损坏的文件,几乎没有CPU时间。
- 现在,文本文件的换行可能不是必需的,但它是一个有用的约定,使大多数UNIX工具能够以一致的结果一起工作。这根本不是一个虫子。
- 我们很多人根本不使用Unix工具,我们也不在乎。
- 它不仅仅是Unix工具,任何工具都能更好地工作和/或更简单地编码,前提是它可以采用合理的文件格式。
- @萨姆·沃特金斯同意简单明确的格式是好的。然而,代码仍然需要验证,而不是假设数据符合格式。
- @梅斯特里翁:这是一个无用的遗产,来自于一套符合愚蠢标准的坏工具。这些极端主义编程的产物(即所有的文件!所有的事情都应该是纯文本的!)他们并没有在发明后不久死去,因为在特定的历史时刻,他们是唯一可用的工具。C是由C++取代的,它不是POSIX的一部分,它不需要EOL在EOF,并且它的用法是(明显)被* nix Ludidis劝阻。
- PokOVNIKOV.PH"C被C++取代"
- @事实上,这些年来,数据格式和基于文本的技术越来越多。XML/HTML、JSON、YAML以及HTTP、RPC、SOAP、REST等协议。这些都不是遗产,对于工具应该如何处理行有一个固定的约定既不无用也不愚蠢。
- @Mestrelion编程越来越缺乏科学依据。越来越多的没受过教育的人开始称自己为程序员。大公司往往会在行业中制造更多的技术债务,以扼杀小企业。这就是这些协议的创建方式。有一个固定的惯例"没人在乎"既不是无用的也不是愚蠢的。有一个惯例"我们必须以一个不可见的字符结束每个文件"是。
除了上述实际原因之外,如果Unix的创建者(Thompson,Ritchie,et al.)或他们的multics前辈意识到使用行终止符而不是行分隔符有一个理论上的原因,我也不会感到惊讶:使用行终止符,您可以对所有可能的行文件进行编码。使用行分隔符,零行文件和包含单个空行的文件之间没有区别;它们都被编码为包含零字符的文件。
所以,原因是:
因为这就是posix定义它的方式。
因为有些工具期待它或者没有它就"行为不端"。例如,如果最后一个"行"没有以换行符结尾,那么wc -l将不计算在内。
因为它简单方便。在Unix上,cat只起作用,而且不复杂。它只复制每个文件的字节,不需要任何解释。我不认为有一个dos等同于cat。使用copy a+b c将导致文件a的最后一行与文件b的第一行合并。
因为零行的文件(或流)可以与一个空行的文件区分开来。
一个单独的用例:当你的文本文件被版本控制时(在本例中,特别是在Git下,尽管它也适用于其他人)。如果将内容添加到文件结尾,则之前最后一行的行将被编辑为包含换行符。这意味着blame通过查看文件来确定最后一次编辑该行的时间,将显示文本添加,而不是实际希望看到的提交。
还有一个实际的编程问题,即文件末尾缺少新行:readbash内置(我不知道其他read实现)无法按预期工作:
1 2 3 4 5
| printf $'foo
bar' | while read line
do
echo $line
done |
这只打印foo!原因是,当read遇到最后一行时,它将内容写入$line但返回退出代码1,因为它达到了EOF。这打破了while循环,因此我们永远无法到达echo $line部分。如果要处理这种情况,必须执行以下操作:
1 2 3 4 5
| while read line || [ -n"${line-}" ]
do
echo $line
done < <(printf $'foo
bar') |
也就是说,如果read由于文件末尾的一个非空行而失败,则执行echo。当然,在这种情况下,输出中会有一个额外的换行符,而不是输入中的换行符。
可能只是一些解析代码期望它存在。
我不确定我是否会认为这是一个"规则",而且这肯定不是我信奉的宗教。最合理的代码将知道如何逐行分析文本(包括编码)(任何选择的行尾),最后一行是否有换行符。
事实上,如果你以一条新的线结束:在EOL和EOF之间有(理论上)一条空的最后一条线吗?想一想……
- 这不是一条规则,而是一种惯例:一条线是以一条线的末端结束的东西。所以不,在EOL和EOF之间没有"空的最后一行"。
- @梅斯特里翁:但这个角色的名字不是"行尾",而是"换行"和/或"换行"。行分隔符,而不是行终止符。结果是最后一个空行。
- 没有(SANE)工具会将文件的最后一个EOL(CR、LF等)算作一个额外的空行。如果没有结束的EOL,那么所有POSIX工具都不会将文件的最后一个字符计数为一行。无论EOL字符名是"换行"还是"回车"(没有名为"换行"),对于所有实用的pupose,明智的工具都将其视为行终止符,而不是行分隔符。
- @梅斯特里翁,你确定"线路终结者"是健全的吗?找几个非程序员做一个快速调查。你会很快意识到线条的概念更接近于"线条分隔符"的概念。"线路终结者"的概念很奇怪。
- @mestrelion如果没有"健全"的工具可以将最后一个EOL计算为创建一个新的空行,那么用户如何到达下一行来向其添加内容呢?我想在你看来,总是有一个额外的EOL,即使在一个完全"空"的文件?
- @Sahuagin:这不是我的视图,这是POSIX标准定义行的方式。一个0字节的空文件有0行,因此没有eol,而一个文件被认为只有一个空行,它确实需要eol。另外请注意,只有当您想计算一个文件中的行数时,这才是相关的,因为很明显,任何编辑器都会让您"进入"下一行(或第一行),而不管是否已经存在EOL。
- @因此,用户可以浏览到不存在的行,并且文件中可能存在没有行可存在的数据。我理解这是一个标准,但你的意思是不这样做是"疯狂的"。实际上,它似乎只是使许多情况无效,而这些情况很容易是有效的,当给定一个不必要的"无效"文本文件时,允许处理文件的应用程序表现不佳。
- @Sahuagin:也许"理智"是一个严厉的词,但我的观点是:如果有一个由标准正式定义的惯例,没有理由不采用它。并且,使用健壮性原则"发送内容要保守,接受内容要自由",处理文本的工具(解析器、编译器、过滤器)应该能够在任何可能的时候处理这两种情况,但是文本编辑器应该尝试为每行创建带有终止EOL的文件,包括最后一行。
Why should (text) files end with a newline?
因为:
许多程序表现不好,或者没有它就会失败。
即使能够很好地处理文件的程序也缺少结束的'
',该工具的功能可能无法满足用户的期望——在这个角落的案例中,这可能不清楚。
程序很少禁止最终的'
'(我不知道有)。
然而,这引出了下一个问题:
What should code do about text files without a newline?
最重要的是,不要编写假定文本文件以换行符结尾的代码。假设一个文件符合某种格式,就会导致数据损坏、黑客攻击和崩溃。例子:
1 2 3 4 5 6 7 8
| // Bad code
while (fgets(buf, sizeof buf, instream)) {
// What happens if there is no
, buf[] is truncated leading to who knows what
buf[strlen(buf) - 1] = '\0'; // attempt to rid trailing
...
} |
如果需要最后一个尾随的'
',请提醒用户其不在,并采取措施。Lows,验证文件的格式。注意:这可能包括对最大行长度、字符编码等的限制。
明确定义,文档,代码对缺失的最终'
'的处理。
尽可能不要生成缺少结尾'
'的文件。
多年来我一直在思考这个问题。但我今天遇到了一个很好的理由。
想象一个每行都有记录的文件(例如:一个csv文件)。电脑在文件的末尾写记录。但它突然坠毁了。最后一行完成了吗?(情况不太好)
但是如果我们总是终止最后一行,那么我们就会知道(只需检查最后一行是否终止)。否则,为了安全起见,我们可能每次都要丢弃最后一行。
现在已经很晚了,但是我在文件处理中遇到了一个错误,那是因为文件没有以空换行符结尾。我们使用sed处理文本文件,sed省略了输出的最后一行,这导致无效的json结构,并将进程的其余部分发送到失败状态。
我们所做的就是:
有一个示例文件称:foo.txt,其中包含一些json内容。
1 2 3 4 5 6
| [{
someProp: value
},
{
someProp: value
}] <-- No newline here |
该文件是在寡妇机器中创建的,窗口脚本正在使用powershall命令处理该文件。一切都好。
当我们使用sed命令sed 's|value|newValue|g' foo.txt > foo.txt.tmp处理相同的文件时新生成的文件是
1 2 3 4 5
| [{
someProp: value
},
{
someProp: value |
然后,由于无效的JSON,它使其余的进程失败了。
所以用空行结束文件总是一个好的做法。
我一直觉得,这条规则来自于分析一个没有结尾换行的文件时的困难。也就是说,如果行尾是由eol字符或eof定义的,那么您将最终编写代码。假设一条线以EOL结束是简单的。
不过,我相信这个规则是从需要换行的C编译器派生出来的。正如"文件结尾没有换行"编译器警告中指出的那样,include不会添加换行。
假设正在处理文件,而另一个进程仍在生成该文件。
可能跟那有关?指示文件已准备好处理的标志。
我个人喜欢源代码文件末尾的新行。
因此,它可能起源于Linux或所有UNIX系统。我记得这里有编译错误(如果我没弄错的话是gcc),因为源代码文件没有以一个空的新行结尾。为什么这样做让人疑惑。
嗯,这是个人风格和意见的问题。
在过去,我没有把这句话放在新词上。保存的字符意味着通过14.4K调制解调器的速度更快。
稍后,我将换行,这样使用shift+downarrow可以更容易地选择最后一行。