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


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


1096
2018-04-08 12:16


起源


只是一个挑剔。它不是文件末尾的“新行”。这是最后一行末尾的“换行符”。另外,请查看相关问题的最佳答案: stackoverflow.com/questions/16222530/... - gcb
只是为了挑选更多,他实际上并没有写“新线”,他写了“换行”,这是正确的。 - sindrenm
不熟悉,但想知道我的确是因为多余的换行实际上破坏事物的案例数量有点太高了我的口味 - tobibeer
我目前正在使用Node.js流来逐行解析纯文本数据,并且缺少终端换行是令人讨厌的,因为我必须在流的输入端完成时添加额外的逻辑/关闭以确保最后一行得到处理。 - Mark K Cowan
该 方式Unix问候 它在文件末尾的一般行为如下:\ n字符不起始行;相反,他们结束了他们。因此,\ n是行终止符,而不是行分隔符。第一行(像所有行一样)不需要\ n来启动它。最后一行(与所有行一样)需要\ n来结束它。文件末尾的\ n不会创建其他行。但是,有时文本编辑器会在那里添加一个可见的空白行。甚至emacs都这样做, 可选。 - MarkDBlackwell


答案:


因为那是 POSIX标准如何定义 线

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

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

在终端模拟器上工作时,本指南至少有一个很大的优势:所有Unix工具都期望这个约定并使用它。例如,与文件连接时 cat,换行符终止的文件与不具有换行符的文件具有不同的效果:

$ more a.txt
foo$ more b.txt
bar
$ more c.txt
baz
$ cat *.txt
foobar
baz

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

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

从今起 非POSIX兼容 系统(现在主要是Windows),重点是没有意义:文件通常不以换行符结束,并且行的(非正式)定义可能例如是“文本” 分离 by newlines“(注意重点)。这完全有效。然而,对于结构化数据(例如编程代码),它使解析最简单地更复杂:它通常意味着必须重写解析器。如果解析器最初是用POSIX定义编写的,那么修改令牌流而不是解析器可能更容易 - 换句话说,在输入的末尾添加“人工换行”令牌。


1029
2018-04-08 12:46





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

GCC警告它不是因为它 不能 处理文件,但因为它 不得不 作为标准的一部分。

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

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

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

参考: GCC / GNU邮件存档


246
2018-04-08 12:26



请编写好的程序然后允许在处理时在需要的地方插入换行符,或者能够正确处理“丢失”的那些......事实上,这些都没有丢失 - tobibeer
@BilltheLizard,有什么例子 “某些程序在处理文件的最后一行时遇到问题,如果它不是换行符”? - Pacerier
@Pacerier wc -l 如果文件不是换行符,则不会计算文件的最后一行。也, cat 如果第一个文件的最后一行不是换行符,则将文件的最后一行与下一个文件的第一行连接成一行。几乎任何正在寻找新行作为分隔符的程序都有可能弄乱这个问题。 - Bill the Lizard
@BilltheLizard,我的意思是 wc 具有 已被提及.... - Pacerier
@BilltheLizard,我的不好,澄清一下:如果程序没有换行终止,那么在处理文件最后一行时遇到问题的程序的例子是什么(除了已经在线程上大量提到的那些程序之外) cat 和 wc)? - Pacerier


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

如果我们想成为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标准(或任何OS级标准)处理文件是不切实际的。

因此,我们可以相对确信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

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

正如在这个帖子中提到的其他人:如果你想要怎么做 cat 两个文件的输出只是一行而不是两行?换一种说法, cat 做它应该做的事情。

man 的 cat 只提到读取输入到EOF,而不是<newline>。请注意 -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我们 curld) - 除非我们的意图真的算在内 线 符合POSIX标准。

结论

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

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

随意发布用于JS,HTML和CSS的用例,我们可以在其中检查跳过EOL如何产生负面影响。


89
2017-08-15 06:31



rfc编辑器链接应该是 rfc-editor.org/old/EOLstory.txt - gcali
POSIX没有标记在问题中...关于MVS / OS线路结尾的问题?或MS-DOS行结尾?顺便说一下,所有已知的posix系统都允许文本文件没有最后一行结尾(没有找到符合posix标准的声明系统,“内核文件”在内核中有特殊处理,以便在没有的情况下插入正确的换行符它) - Luis Colorado
我修复了EOLstory.txt的链接,但因为我只添加了 /旧 它不会让我保存它。 - user34660


它可能与此有关 之间的区别

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

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

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

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

1 first line
2 middle line
3 last line
4

59
2018-04-08 12:29



+1。在遇到这个问题时,我发现了这个问题。它是 非常 令人讨厌的Eclipse显示这个“假的”最后一行,如果我删除它,那么git(以及所有其他期望EOL的unix工具)都会抱怨。另请注意,这不仅仅是在2005年:Eclipse 4.2 Juno仍然存在这个问题。 - MestreLion
@MestreLion,续集于 stackoverflow.com/questions/729692/... - Pacerier


有些工具期待这一点。例如, wc 期待这个:

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

38
2017-10-12 14:16



我说,我不会说“有些” 最 工具期望对于文本文件,如果不是全部的话。 cat,git,diff,wc,grep,sed ...列表很大 - MestreLion
也许有人可以这么说 wc 不 期望 这就像它只是在POSIX定义的“线”中工作一样,而不是大多数人对“线”的直观理解。 - Guildenstern
@Guildenstern直观的定义是为了 wc -l 打印 1 在这两种情况下,但有些人可能会说第二种情况应该打印出来 2。 - Flimm
@Flimm如果你想到的话 \n 作为行终止符,而不是像POSIX / UNIX那样的行分隔符,然后期望第二个案例打印2绝对是疯了。 - semicolon


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

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

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


18
2018-04-08 12:21



GCC不能处理文件,它必须将警告作为C标准的一部分。 - Bill the Lizard
好点,用适当的部分更新) - cgp
IIRC,MSVC 2005抱怨C文件以不完整的行结束,可能拒绝编译它们。 - Mark K Cowan


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

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

但是,如果您有文本文件格式 要求 在换行符中,您可以非常便宜地获得简单的数据验证:如果文件以最后没有换行符的行结束,则表示文件已损坏。每行只有一个额外字节,您可以高精度地检测损坏的文件,几乎没有CPU时间。


12
2018-04-08 12:41



如今在EOF换行 文本 文件可能不是必需的,但它是有用的 惯例 这使得大多数unix工具能够以一致的结果协同工作。这根本不是一个bug。 - MestreLion
很多人根本不使用Unix工具,我们也不在乎。 - DaveWalley
它不仅仅是unix工具,如果它可以采用合理的文件格式,任何工具都可以更好地工作和/或编码更简单。 - Sam Watkins
@MestreLion这是一个 无用的遗产 从一组符合愚蠢标准的坏工具。这些文物 极端主义编程(即一切都是文件!一切都应该说明文!)并没有在发明之后很快就死掉,因为它们是历史上某一时刻唯一可用的工具。 C被C ++取代,它不是POSIX的一部分,它在EOF中不需要EOL,并且它的使用(显然)被* nix luddists劝阻。 - polkovnikov.ph
@ polkovnikov.ph“C被C ++取代”嗯...... - minexew