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

Wil*_*son 1375 unix newline file text-files

我假设这里的每个人都熟悉所有文本文件应以换行符结尾的格言.多年来我一直都知道这个"规则",但我一直在想 - 为什么?

Kon*_*lph 1290

因为这是POSIX标准定义一条线的方式:

3.206线
一系列零个或多个非<newline>字符加上一个终止<newline>字符.

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

在终端仿真器上工作时,本指南至少有一个硬性优势:所有Unix工具都希望使用此约定并使用它.例如,当连接文件时cat,由换行符终止的文件将具有与不具有以下内容的文件不同的效果:

$ more a.txt
foo
$ more b.txt
bar$ more c.txt
baz
$ cat {a,b,c}.txt
foo
barbaz
Run Code Online (Sandbox Code Playgroud)

并且,正如前面的示例所示,当在命令行上显示文件时(例如,通过more),换行符的换行文件会导致正确的显示.未正确终止的文件可能会出现乱码(第二行).

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


不同的想法:如果换行没有终止行,那么制作cat有用的命令要困难得多:如何创建一个连接文件的命令,以便

  1. 它将每个文件的开头放在一个新行上,这是你想要的95%的时间; 但
  2. 它允许合并两个文件的最后一行和第一行,如上面的示例b.txtc.txt

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

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


现在,在非POSIX兼容系统(现在主要是Windows)上,重点是:文件通常不以换行符结束,而行的(非正式)定义可能是" 由换行符分隔的文本" (注意重点).这完全有效.但是,对于结构化数据(例如编程代码),它使解析变得更加复杂:它通常意味着必须重写解析器.如果解析器最初是用POSIX定义编写的,那么修改令牌流而不是解析器可能更容易 - 换句话说,在输入的末尾添加"人工换行"令牌.

  • @DougCoburn这个答案曾经有一个详尽的技术讨论,解释了为什么这是错误的,以及为什么POSIX做了正确的事情.不幸的是,这些评论最近被一个过分热心的主持人删除了.简而言之,它不是解析复杂性; 相反,你的定义使得以一种既有用又一致的方式创作诸如`cat`之类的工具变得更加困难. (12认同)
  • 我真的不明白这里对 POSIX 的所有尖酸刻薄。这就像争论数组索引应该从 0 还是 1 开始一样。0 提供了技术优势,1 更熟悉,但只要一致,任何一个都可以工作。POSIX 的编辑器仍然为您处理它,就像他们处理 LF 与 CR/LF 的方式一样。旁注:POSIX 方式的其他技术优势是 1) 它允许您执行诸如将文本文件拆分为 4KB 块之类的操作,而不必担心中线发生拆分,2) (最重要的)它允许使用“cat”等工具也可以在没有特殊考虑的情况下处理二进制文件。 (11认同)
  • Unix 行终止符约定是 Unix 哲学的一个实例:“在需要时使数据复杂化,而不是程序复杂化”。通过指定行必须以换行符结尾的约定,您可以简化所有程序和许多 POSIX API 的实现。这种简单性意味着有时事情并不完美(特别是在处理不遵循约定的文件时),但是当您将许多工具堆叠到一个复杂的管道中时,就更容易推理出为什么事情不能像当工具本身并没有太智能时,这是可以预料到的。 (9认同)
  • @BT我只是指Windows来指出POSIX规则没有意义的情况(换句话说,我是在给你扔骨头)。我很高兴再也没有在讨论中提及它。但是,那么您的主张就没有意义了:在POSIX平台上,讨论具有不同行尾约定的文本文件完全没有意义,因为没有理由产生它们。有什么好处?实际上没有。—总之,我**真的**不理解这个答案(或POSIX规则)引起的仇恨。坦率地说,这是完全不合理的。 (6认同)
  • @Andrew 不放换行符 * 也是 * 一项要求,而且绝对不会更便宜或更容易。无论哪种情况,要求都是“遵守标准”。您声称省略换行符会使任何事情变得更容易是谬论。 (6认同)
  • @DougCoburn 这个问题与实际的 POSIX 标准无关,而是与存在允许用户“轻松且不知不觉地违反标准”的工具有关。允许您查看、删除和保存文件而无需终止换行符的编辑器是一个损坏的编辑器。当问题是程序不遵循标准时,您就将责任归咎于标准。标准是好还是坏并不重要。文本编辑器应该始终创建符合标准的文件,而用户不需要了解标准。 (6认同)
  • @Leon POSIX规则是关于减少边缘情况的。而且效果如此出色。我实际上对人们如何理解这一点感到茫然:这是一条线的最简单,自洽的定义。 (5认同)
  • @BT我想您是在以我更便捷的工作流程的* example *为决策背后的* reason *。不是,这只是后果。原因是POSIX规则是最简单的规则,它使解析器中的行处理最容易。我们甚至引起争论的唯一原因是Windows的处理方式有所不同,因此,有许多工具无法在POSIX文件上运行。如果每个人都使用POSIX,就不会有任何问题。但是人们抱怨POSIX,而不是Windows。 (5认同)
  • 软件应该正确处理极端情况,而不是强制人们遵守这些愚蠢的规则(有很多愚蠢的事情浪费了开发人员的生命)。 (4认同)
  • 几年前,我在源文件顶部的斜杠星号注释标题中遇到了一个奇怪的语法错误。评论是正确的;让我发疯了。然后,我意识到该文件和所有其他文件在进入编译器之前已连接起来。令人惊讶的是,之前的文件以斜杠注释结束,并且没有换行符,因此下一个文件的初始斜杠星号被注释掉了。 (4认同)
  • @JShorthouse 我同意。例如,我喜欢 github 在您没有以换行符结束文件时发出警告的方式。当我第一次发表评论时,我没有考虑按大小边界而不是换行符边界分割大文本(即日志)文件的情况。POSIX 定义现在对我来说有意义了。 (4认同)
  • 尽管现在纠正起来非常不切实际,但很明显POSIX在定义界线时犯了一个错误-作为有关此问题的大量问题的证据。应该将一行定义为零个或多个以&lt;eol&gt;,&lt;eof&gt;或&lt;eol&gt; &lt;eof&gt;结尾的字符。解析器的复杂性不是一个有效的问题。尽可能将复杂性从程序员的头转移到库中。 (3认同)
  • 很公平 - 不幸的是,它们被删除了。我很想知道为什么这仍然被认为是“正确”的事情。 (3认同)
  • @KonradRudolph 我在编辑历史记录中没有看到任何内容。它不应该在编辑历史中吗?还是在有历史之前?还是09年的... (3认同)
  • @adjenks在此答案下,以前曾经有20条评论讨论此问题。它们已删除,未经编辑。无论如何,我刚刚编辑了答案,以解释为何POSIX的换行符定义更实用,以及如何使替代定义看起来同样方便(Doug建议的定义不够)。 (3认同)
  • @KonradRudolph 如果文件结束,当然最后一行结束。IMO 这是每个人的期望。文件已结束,但您希望该行继续——这很奇怪。无论如何,我无法改变 `sed`、`wc` 等的行为。 (3认同)
  • 这与窗户无关,不要建造稻草人。从字面上看,除了你之外没有人在这里谈论窗户。我同意强制每个文件以换行符结尾使得按行解析内容(微不足道)更容易。我也同意这样做可以使连接可​​能代表不按行分割的块的文件变得更容易(微不足道)。我不同意的是,让解析变得稍微容易一点值得强迫几乎每个人在文件末尾添加通常不必要的换行符。编写没有结束换行符的文件的程序也没有借口。 (3认同)
  • @安德鲁当然有可能。但我看不出这有什么好处*无论如何*。 (3认同)
  • @adjenks 不在答案中,而是在评论中。 (2认同)
  • 串联问题的解决方案是不要将文件视为它们都采用相同的编码。如果我们谈论的是源代码文件,那么将它们连接起来使得第一个文件的最后一行和第二个文件的第一行合并成一行几乎没有任何意义。上下文很重要。尝试硬塞所有东西以使其适合您的 5% 用例几乎肯定是一个糟糕的决定。Unix 和 linux 之前并没有回避命令行标志,为什么要回避使用 -r(用于原始)或带有 `cat` 的东西?我认为 POSIX 实际上在这里犯了一个错误 (2认同)
  • @Leon 您不需要更改任何这些工具的行为,当在由此类工具生成的任何文件上使用时,它们的行为已经正确且一致,或者以其他方式遵守 POSIX 准则。你甚至如何创建一个没有的文本文件?这在 GNU/BSD/POSIX 系统上已经不是小事了。 (2认同)
  • @KonradRudolph 错误。不放换行符**不是**要求:用户总是可以放或不放,选择权取决于他们。他们从来没有以这种方式受到过约束。然而,一些工具——即较旧的 Unix 工具——需要换行符。所以不,前者是**不**“遵守标准”,它是“制定你自己的个人/团体标准”,而后者是,“这就是我们要做的,现在遵守我们的任意标准”。这不是为了更容易 - 我也没有说它 - 我说它*更好*。不标准化不必要的要求会更好。 (2认同)
  • @Andrew当然有这样的要求:您的规则必须在内部保持一致(否则,工具将不知道终端换行符是否表示多余的空行)。而且“用户”不会参与其中。*工具*需要产生一致的文件。工具可以同意将换行符视为行分隔符,而不是行终止符(这是您的建议,以及许多Windows工具所做的事情),但是–与您所说的相反–这并不能使任何事情变得更好,它只是使它*不同*。如您所言,如果我们不需要任何标准,那么我们将不再进行讨论。 (2认同)
  • @DougCoburn _“解析器复杂性不是一个有效的问题。”_它绝对是 Unix(以及 POSIX)[“越差越好”](https://en.wikipedia.org/wiki/Worse_is_better)方法中的一个问题,与其他一些操作系统中使用的[“MIT 方法”](https://en.wikipedia.org/wiki/Worse_is_better#The_MIT_approach) 相比。WiB 有其优点和缺点,就像 MIT 一样,但毫无疑问,在某些事情上使用 WiB 而在其他事情上使用 MIT 会更糟糕,因为这会让你同时拥有两者的缺点。 (2认同)

Bil*_*ard 269

每一行都应以换行符结尾,包括最后一行.如果某个程序不是换行符,则会在处理文件的最后一行时遇到问题.

GCC警告它不是因为它无法处理文件,而是因为它必须作为标准的一部分.

C语言标准说一个非空的源文件应以换行符结尾,换行符前面不应该有反斜杠字符.

由于这是一个"shall"子句,我们必须发出违反此规则的诊断消息.

这在ANSI C 1989标准的2.1.1.2节中.ISO C 1999标准的5.1.1.2节(也可能是ISO C 1990标准).

参考:GCC/GNU邮件存档.

  • 请编写好的程序,然后允许在处理时在需要的地方插入换行符,或者能够正确处理"丢失"的那些...实际上,不会丢失 (15认同)
  • @BilltheLizard,有什么例子*"某些程序在处理文件的最后一行时遇到问题,如果它不是换行符"*? (4认同)
  • @Pacerier`wc -l`如果不是换行符,则不会计算文件的最后一行.此外,如果第一个文件的最后一行不是换行终止,`cat`将加入文件的最后一行,并将下一个文件的第一行合并为一行.几乎所有寻找新行作为分隔符的程序都有可能弄乱这个问题. (4认同)
  • @BilltheLizard,我的意思是`wc`已经[已被提及](http://stackoverflow.com/a/7741505/632951).... (2认同)
  • @BilltheLizard,我的坏,澄清一下:如果程序没有换行终止,那么在处理文件最后一行时遇到问题的程序的例子是什么(除了那些已经在线程上被大量提及的那些例如`cat`和`wc`)? (2认同)
  • 如果最后一行未使用行终止符终止,则 Visual Studio 资源编译器 (rc) 会阻塞。 (2认同)
  • C++14 标准的说法略有不同:“非空且不以换行符结尾的源文件......应被处理**,就好像一个额外的换行符被附加到文件**”[强调]。这似乎是多余的,因为翻译的第 1 阶段需要插入“行尾指示符的换行符”[lex.phases]。 (2认同)

小智 109

这个答案是尝试技术答案而不是意见.

如果我们想成为POSIX纯粹主义者,我们将一行定义为:

一系列零个或多个非<newline>字符加上一个终止<newline>字符.

资料来源:http://pubs.opengroup.org/onlinepubs/9699919799/basedefs/V1_chap03.html#tag_03_206

一条不完整的行:

文件末尾的一个或多个非<newline>字符的序列.

资料来源:http://pubs.opengroup.org/onlinepubs/9699919799/basedefs/V1_chap03.html#tag_03_195

文本文件为:

包含组织为零行或多行的字符的文件.这些行不包含NUL字符,长度不能超过{LINE_MAX}个字节,包括<newline>字符.尽管POSIX.1-2008不区分文本文件和二进制文件(请参阅ISO C标准),但许多实用程序在操作文本文件时仅产生可预测或有意义的输出.具有此类限制的标准实用程序始终在其STDIN或INPUT FILES部分中指定"文本文件".

资料来源:http://pubs.opengroup.org/onlinepubs/9699919799/basedefs/V1_chap03.html#tag_03_397

字符串为:

由第一个空字节终止并包括第一个空字节的连续字节序列.

资料来源:http://pubs.opengroup.org/onlinepubs/9699919799/basedefs/V1_chap03.html#tag_03_396

从这以后,我们可以得出的唯一的一次,我们将有可能遇到什么类型的问题是,如果我们处理一个概念的文件或文件为文本文件(是一个文本文件是零的组织或更多行,我们知道的行必须以<newline>结束.

例证:wc -l filename.

wc我们的手册中我们读到:

行被定义为由<newline>字符分隔的字符串.

对JavaScript,HTML和CSS文件有什么影响,那么它们是文本 文件?

在浏览器,现代IDE和其他前端应用程序中,在EOF中跳过EOL没有问题.应用程序将正确解析文件.由于并非所有操作系统都符合POSIX标准,因此非OS工具(例如浏览器)根据POSIX标准(或任何操作系统级标准)处理文件是不切实际的.

因此,我们可以相对确信EOF的EOL在应用程序级别几乎没有负面影响 - 无论它是否在UNIX OS上运行.

在这一点上,我们可以自信地说,在客户端处理JS,HTML,CSS时,在EOF上跳过EOL是安全的.实际上,我们可以声明缩小其中任何一个文件,不包含<newline>是安全的.

我们可以更进一步说,就NodeJS而言,它也不能遵守POSIX标准,因为它可以在非POSIX兼容环境中运行.

那我们还剩下什么?系统级工具.

这意味着可能出现的唯一问题是工具努力将其功能与POSIX的语义相结合(例如,如图所示定义一条线wc).

即便如此,并非所有shell都会自动粘贴到POSIX上.例如,Bash不默认为POSIX行为.有一个开关启用它:POSIXLY_CORRECT.

关于EOL价值的思考的食物是<newline>:http://www.rfc-editor.org/EOLstory.txt

保持工具轨道,出于所有实际意图和目的,让我们考虑一下:

让我们使用没有EOL的文件.在撰写本文时,此示例中的文件是一个没有EOL的缩小JavaScript.

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
Run Code Online (Sandbox Code Playgroud)

请注意,cat文件大小恰好是各个部分的总和.如果JavaScript文件的串联是JS文件的一个问题,那么更合适的问题是用分号启动每个JavaScript文件.

正如在这个帖子中提到的其他人一样:如果你想要cat两个文件的输出只是一行而不是两行呢?换句话说,cat它应该做什么.

所述mancat唯一提到读取输入到EOF,不<换行符>.请注意,-n切换也cat将打印出非<换行>终止行(或不完整行)作为一行 - 计数从1开始(根据man.)

-n编号输出行,从1开始.

现在我们已经理解了POSIX如何定义一条线,这种行为变得模棱两可,或者真的不合规.

了解给定工具的目的和合规性将有助于确定使用EOL结束文件的重要性.在C,C++,Java(JAR)等中......一些标准将规定有效性的换行符 - JS,HTML,CSS没有这样的标准.

例如,不要使用wc -l filename一个可以做的awk '{x++}END{ print x}' filename,并且放心,任务的成功不会受到我们可能想要处理的文件的危害,我们没有写入(例如第三方库,例如缩小的JS curl) - 除非我们意图是真正计算符合POSIX标准的.

结论

现实生活中的用例非常少,在EOF中为某些文本文件(如JS,HTML和CSS)跳过EOL会产生负面影响 - 如果有的话.如果我们依赖<newline>存在,我们将工具的可靠性仅限于我们创作的文件,并将自己打开以防止第三方文件引入的潜在错误.

故事的道德:在EOF中没有依赖EOL的弱点的工程师工具.

随意发布用例,因为它们适用于JS,HTML和CSS,我们可以检查跳过EOL如何产生负面影响.

  • POSIX 没有在问题中标记......关于 MVS/OS 行结尾的问题?或 MS-DOS 行尾?顺便说一句,所有已知的 posix 系统都允许没有最后一行结尾的文本文件(没有发现符合 posix 的声明系统的案例,其中“文本文件”在内核中具有特殊处理以插入适当的换行符,以防万一它没有它) (3认同)
  • _“现实生活中很少有跳过......的用例”_。**不正确。** 在现实生活中,我每天都会检查代码,处理由于文件缺少尾随“换行符”而导致的无用合并差异是浪费时间。为了保持一致性,每一行(甚至文件中的最后一行)都应该正确终止。 (2认同)

Von*_*onC 60

它可能与以下区别有关:

  • 文本文件(每行应该以行尾结束)
  • 二进制文件(没有真正的"行"可以说,文件的长度必须保留)

如果每一行都以行尾结束,这就避免了,例如,连接两个文本文件会使第一行的最后一行进入第二行的第一行.

另外,编辑器可以在加载时检查文件是否以行尾结束,将其保存在本地选项'eol'中,并在写入文件时使用它.

几年前(2005年),许多编辑(ZDE,Eclipse,Scite,......)确实"忘记"了最终的EOL,这并不是很受欢迎.
不仅如此,他们还错误地将最终EOL解释为"开始一条新线",并且实际上开始显示另一条线,就好像它已经存在一样.
与在上面的一个编辑器中打开它相比,使用像vim这样表现良好的文本编辑器的"正确"文本文件非常明显.它在文件的实际最后一行下方显示了一条额外的行.你看到这样的事情:

1 first line
2 middle line
3 last line
4
Run Code Online (Sandbox Code Playgroud)

  • +1.在遇到这个问题时,我发现了这个问题.Eclipse显示这个"假的"最后一行是非常烦人的,如果我删除它,那么git(以及所有其他期望EOL的unix工具)都会抱怨.另请注意,这不仅仅是在2005年:Eclipse 4.2 Juno仍然存在这个问题. (9认同)

Fli*_*imm 42

有些工具期待这一点.例如,wc期望这样:

$ echo -n "Line not ending in a new line" | wc -l
0
$ echo "Line ending with a new line" | wc -l
1
Run Code Online (Sandbox Code Playgroud)

  • 我不会说"一些",我说*大多数*工具都希望文本文件,如果不是全部的话.cat,git,diff,wc,grep,sed ...列表很大 (20认同)
  • @Flimm 如果您将 `\n` 视为行终止符,而不是像 POSIX/UNIX 那样作为行分隔符,那么期望第二种情况打印 2 绝对是疯狂的。 (2认同)

Enr*_*lis 25

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

因为这是最明智的选择。

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

one\n
two\n
three
Run Code Online (Sandbox Code Playgroud)

where\n表示换行符,在 Windows 上是\r\n,一个回车符后跟换行符,因为它太酷了,对吧?

这个文件有多少行?Windows 说 3,我们说 3,POSIX (Linux) 说该文件已损坏,因为\n它的末尾应该有一个。

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

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

  • Windows 说two因为文件是“由换行符分隔的行”(什么?);
  • POSIX 说two\n,并补充说这是一句真实、诚实的话。

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

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

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

one\n
two\n
threethreethreethree
Run Code Online (Sandbox Code Playgroud)

相反,尝试交换第二行和第三行......你会得到这个:

one\n
threetwo\n
Run Code Online (Sandbox Code Playgroud)

所以

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

这实在是太拗口了,对吧?

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

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

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

选择 POSIX 的后果是什么?

顶部的文件有点损坏,我们需要一些技巧来处理它。

认真

在前面的文本中,我是挑衅性的,因为处理末尾缺少 的文本文件\n迫使您使用临时标记/黑客来处理它们。你总是需要一个if/else来使事情正常工作,其中处理损坏行的分支仅处理损坏行,所有其他行都采用另一个分支。这有点种族主义,不是吗?

我的结论

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

  • 文件自然地被视为一系列行
  • 一行不应该是这样或那样,取决于它在文件中的位置
  • 空文件不是一行文件,拜托!
  • 您不应该被迫对代码进行修改

是的,Windows确实鼓励您省略结尾的\r\n. 如果您想要下面的两行文件,则必须省略尾随\r\n,否则文本编辑器会将其显示为 3 行文件: 在此输入图像描述

  • 你的回答让我不同意 posix 选择。它不必要地引入了无效的文件状态,并且使“换行符”的含义不正确。“换行符”应该被称为“行标记”,它是唯一将文本内容转换为行的东西,没有它,内容(由于某种原因)毫无意义。 (2认同)
  • “newline”的含义是它创建了一个新行,但显然它没有。相反,它使当前的非行变成行。“行终止符”确实有效。但我仍然认为我不同意有不必要的无效状态。没有理由“text\ntext”不应该是可解读的文本。 (2认同)

cgp*_*cgp 19

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

海湾合作委员会警告你,因为它是C标准的一部分.(显然是第5.1.1.2节)

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

  • GCC不能处理文件,它必须将警告作为C标准的一部分. (5认同)

Rob*_*ton 13

一个单独的用例:当你的文本文件受版本控制时(在这种情况下特别是在git下,虽然它也适用于其他人).如果将内容添加到文件末尾,则之前最后一行的行将被编辑为包含换行符.这意味着blame查找文件以找出上次编辑该行的时间将显示文本添加,而不是您实际想要查看之前的提交.

  • 您可以使用 -w 标签来忽略空白更改,但它们不是默认值。 (3认同)
  • diff 和blame 应该只是更新以检测“新行”而不是“新行”(`\n`)。问题解决了。 (2认同)

Ste*_*fan 12

这源于使用简单终端的早期阶段.换行符char用于触发传输数据的"刷新".

今天,不再需要newline char.当然,如果换行不存在,许多应用程序仍有问题,但我认为这些应用程序中存在错误.

但是,如果你有一个需要换行符的文本文件格式,那么你可以非常便宜地获得简单的数据验证:如果文件以一行最后没有换行的行结束,你知道该文件已损坏.每行只有一个额外字节,您可以高精度地检测损坏的文件,几乎没有CPU时间.

  • 现在,EOF for*text*文件的换行符可能不是必需的,但它是一个有用的*约定*,它使大多数unix工具能够以一致的结果协同工作.这根本不是一个bug. (12认同)
  • 很多人根本不使用Unix工具,我们也不在乎. (11认同)
  • 它不仅仅是unix工具,如果它可以采用合理的文件格式,任何工具都可以更好地工作和/或编码更简单. (11认同)
  • @MestreLion这是一套符合愚蠢标准的坏工具的无用遗产.这些[极端主义编程](http://blog.ezyang.com/2012/11/eremremist-programming/)的文物(即一切文件!一切都应该说明文!)并没有在发明之后很快就死掉,因为它们是在历史的某个时刻唯一可用的工具.C被C++取代,它不是POSIX的一部分,它在EOF中不需要EOL,并且(明显)不鼓励它使用*nix luddists. (6认同)
  • @Sam Watkins同意具有简单定义良好的_formats_很好。但是代码仍然需要验证,而不是假设_data_是符合格式的。 (2认同)
  • @polkovnikov.ph 实际上,这些年来,数据格式和已经变得越来越基于文本。XML/HTML、JSON、YAML 以及 HTTP、RPC、SOAP、REST 等协议。这些都不是遗留的,并且对工具应该如何处理线条有一个可靠的约定既没有用也没有愚蠢。 (2认同)
  • @MestreLion编程越来越缺乏基于科学的知识。越来越多的未受过教育的人开始自称程序员。大公司倾向于在行业中创造更多的技术债务,以杀死小企业。这些协议就是这样创建的。有一个固执的约定“没人在乎”既没有用处也没有愚蠢。有一个约定“我们必须以不可见的字符结尾每个文件”。 (2认同)

jrw*_*ica 11

除了上述实际原因之外,如果Unix的发起者(Thompson,Ritchie等人)或他们的Multics前辈意识到理论上有理由使用行终止符而不是行分隔符,那就不会让我感到惊讶:终结器,您可以编码所有可能的行文件.对于行分隔符,零行文件和包含单个空行的文件之间没有区别; 它们都被编码为包含零个字符的文件.

所以,原因是:

  1. 因为这是POSIX定义它的方式.
  2. 因为有些工具在没有它的情况下期望它或"行为不端".例如,wc -l如果不以换行结束,则不会计算最终的"行".
  3. 因为它简单方便.在Unix上,cat只是工作,它没有复杂的工作.它只是复制每个文件的字节,而不需要解释.我不认为有一个DOS相当于cat.使用copy a+b c将最终将文件的最后一行a与第一行文件合并b.
  4. 因为可以将零行的文件(或流)与一个空行的文件区分开来.


Mar*_*ell 10

大概只是一些解析代码期望它存在.

我不确定我会认为它是一个"规则",它肯定不是我坚持宗教的东西.最明智的代码将知道如何逐行解析文本(包括编码)(任何行结尾的选择),最后一行有或没有换行符.

确实 - 如果你以一条新线结束:理论上是否存在EOL和EOF之间的空白终点线?一个思考......

  • 这不是一个规则,它是一种惯例:*行*是以*行尾*结尾的东西.所以不,EOL和EOF之间没有"空的最后一行". (11认同)
  • @Sahuagin:这不是我的*视图,这是POSIX标准定义一条线的方式.具有0字节的空文件具有0行,因此没有EOL,并且文件被认为仅具有单个空行,它**需要EOL.另请注意,只有当您想要*计算文件中的行时,这才是相关的,因为显然任何编辑器都会让您"到达"下一行(或第一行),无论是否已存在EOL. (4认同)
  • @MestreLion:但是有问题的角色没有被命名为"行尾",它被命名为"换行符"和/或"换行符号".行分隔符,而不是行终止符.结果是最后一条空行. (3认同)
  • 没有(理智)工具会将文件的最后一个EOL(CR,LF等)计为另一个空行.如果没有结束EOL,所有POSIX工具都不会将文件的最后一个字符计为一行.无论EOL字符*名称*是"换行"还是"回车"(没有名称为"换行符"),对于所有实际用途,敏感工具将其视为行*终止符*,而不是行*分隔符*. (2认同)
  • @MestreLion,你确定"行终结者"是理智的吗?抓住一些非程序员并进行快速调查.你会很快意识到**线**的概念更接近"线分离器"的概念."行终结者"的概念[很奇怪](http://stackoverflow.com/questions/729692/why-should-files-end-with-a-newline#comment50420226_729795). (2认同)
  • @MestreLion,如果没有“理智”的工具会将最后一个 EOL 算作创建新的空行,那么用户如何“获取”到下一行以向其添加内容?我想在您看来,即使在完全“空”的文件中,也总是有一个额外的 EOL? (2认同)
  • @MestreLion,因此,用户可以浏览到不存在的行,并且文件中可能存在没有行存在的数据。我知道这是一个标准,但你的意思是不这样做是“疯狂的”。实际上,它似乎使许多本来可以很容易有效的情况变得无效,从而使处理文件的应用程序在给出不必要的“无效”文本文件时表现不佳。 (2认同)

l0b*_*0b0 10

还有一个实际的编程问题,最后缺少换行的文件:readBash内置(我不知道其他read实现)不能按预期工作:

printf $'foo\nbar' | while read line
do
    echo $line
done
Run Code Online (Sandbox Code Playgroud)

这将打印foo!原因是当read遇到最后一行时,它会将内容写入$line但返回退出代码1,因为它达到了EOF.这打破了while循环,所以我们永远不会到达那个echo $line部分.如果要处理这种情况,则必须执行以下操作:

while read line || [ -n "${line-}" ]
do
    echo $line
done < <(printf $'foo\nbar')
Run Code Online (Sandbox Code Playgroud)

也就是说,echo如果read由于文件末尾的非空行而失败.当然,在这种情况下,输出中将有一个额外的换行符不在输入中.


sym*_*ont 9

多年来我一直在想这个.但我今天遇到了一个很好的理由.

想象一下每行都有记录的文件(例如:CSV文件).并且计算机正在文件末尾写入记录.但它突然崩溃了.Gee是最后一行完成的?(不是很好的情况)

但是如果我们总是终止最后一行,那么我们就知道了(只需检查最后一行是否终止).否则我们可能不得不每次丢弃最后一行,只是为了安全起见.

  • 这其实是一个可怕的理由。您的文件系统应该用来处理这个问题。现代文件系统会记录日志,这是一种更好的识别文件写入是否完成的方法,因为它适用于二进制文件和文本文件,并且具有上次尝试写入的实际历史记录。 (3认同)

chu*_*ica 8

为什么(文本)文件以换行符结尾?

许多人表达了,因为:

  1. 许多程序表现不佳,没有程序就会失败.

  2. 即使是处理文件的程序也没有结束'\n',该工具的功能可能无法满足用户的期望 - 在这个角落的案例中可能不清楚.

  3. 程序很少不允许最终'\n'(我不知道任何).


然而,这引出了下一个问题:

代码应该怎么做没有换行的文本文件?

  1. 最重要的 - 不要编写假定文本文件以换行符结尾的代码. 假设文件符合格式会导致数据损坏,黑客攻击和崩溃.例:

    // Bad code
    while (fgets(buf, sizeof buf, instream)) {
      // What happens if there is no \n, buf[] is truncated leading to who knows what
      buf[strlen(buf) - 1] = '\0';  // attempt to rid trailing \n
      ...
    }
    
    Run Code Online (Sandbox Code Playgroud)
  2. 如果'\n'需要最终跟踪,请提醒用户缺席并采取措施.IOWs,验证文件的格式.注意:这可能包括最大行长度,字符编码等的限制.

  3. 明确定义,文档,代码处理缺失的决赛'\n'.

  4. 尽量不要生成缺少结尾的文件'\n'.


Arp*_*pit 6

现在已经很晚了,但我只是在文件处理中遇到了一个错误,这是因为文件没有以空换行符结尾。我们正在处理文本文件,sedsed省略了输出中的最后一行,这会导致无效的 json 结构并将其余进程发送到失败状态。

我们所做的只是:

有一个示例文件说:里面foo.txt有一些json内容。

[{
    someProp: value
},
{
    someProp: value
}] <-- No newline here
Run Code Online (Sandbox Code Playgroud)

该文件是在寡妇机器中创建的,窗口脚本正在使用 PowerShell 命令处理该文件。都好。

当我们使用sed命令处理同一个文件时sed 's|value|newValue|g' foo.txt > foo.txt.tmp

新生成的文件是

[{
    someProp: value
},
{
    someProp: value
Run Code Online (Sandbox Code Playgroud)

和繁荣,由于无效的 JSON,它使其余的过程失败。

因此,以空的新行结束文件始终是一个好习惯。