首页 文章

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

提问于
浏览
1153

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

18 回答

  • 18

    我总是认为规则来自于解析没有结束换行符的文件很困难的日子 . 也就是说,您最终会编写代码,其中行结束由EOL字符或EOF定义 . 假设以EOL结束的行更简单 .

    但是我相信该规则来自需要换行的C编译器 . 正如“No newline at end of file” compiler warning所指出的,#include不会添加换行符 .

  • 3

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

  • 254

    我个人喜欢源代码文件末尾的新行 .

    它可能源于Linux或所有UNIX系统 . 我记得有编译错误(gcc,如果我没有记错的话)因为源代码文件没有以空的新行结束 . 为什么这样做会让人不知道 .

  • 1098

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

    许多人表达了,因为:

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

    • 即使是处理文件的程序也没有结束 '\n' ,工具's functionality may not meet the user'的预期 - 在这个角落的情况下可能不清楚 .

    • 程序很少禁止最终 '\n' (我不知道任何) .


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

    如果没有换行,代码应该对文本文件做些什么?

    • 最重要的 - Do not write code that assumes a text file ends with a newline . 假设文件符合格式会导致数据损坏,黑客攻击和崩溃 . 例:
    // 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
      ...
    }
    
    • 如果需要最终尾随 '\n' ,请提醒用户缺席并采取措施 . IOWs,验证文件的格式 . 注意:这可能包括对最大行长度,字符编码等的限制 .

    • 明确定义,记录代码处理缺失的最终 '\n' .

    • 尽可能不生成缺少结尾 '\n' 的文件 .

  • -7

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

    所以,原因是:

    • 因为这是POSIX定义它的方式 .

    • 因为有些工具需要它或"misbehave"没有它 . 例如,如果 wc -l 不以换行结束,则不会计算最终的"line" .

    • 因为它简单方便 . 在Unix上, cat 只是工作,它没有复杂性 . 它只是复制每个文件的字节,而不需要解释 . 我不是't think there',相当于 cat 的DOS . 使用 copy a+b c 将最终将文件 a 的最后一行与文件的第一行 b 合并 .

    • 因为零行的文件(或流)可以与一个空行的文件区分开来 .

  • 9

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

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

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

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

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

  • 6

    它可能与difference between有关:

    • 文本文件(每行应该以行尾结束)

    • 二进制文件(没有真正的"lines",并且必须保留文件的长度)

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

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

    几年前(2005年),许多编辑(ZDE,Eclipse,Scite,......)做了"forget",最后的EOL,which was not very appreciated .
    不仅如此,他们还错误地解释了最终的EOL,如'start a new line',并且实际上开始显示另一条线,就像它已经存在 .
    与在上面的一个编辑器中打开文本编辑器一样,文本文件编辑器像vim这样的文本编辑器非常明显 . 它在文件的最后一行下方显示了一条额外的行 . 你看到这样的事情:

    1 first line
    2 middle line
    3 last line
    4
    
  • 39

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

    如果我们想成为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字符,长度不能超过个字节,包括<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 文件大小正是其各个部分的总和 . 如果JS文件的串联是JS文件的一个问题,那么更合适的关注点是用分号启动每个JavaScript文件 .

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

    catman 仅提到读取输入到EOF,而不是<newline> . 请注意 cat-n 开关也会打印出非<换行>终止的行(或不完整的行)作为一行 - 计数从1开始(根据 man . )

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

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

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

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

    Conclusion

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

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

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

  • 94

    想象一下,当文件仍由另一个进程生成时,正在处理该文件 .

    它可能与此有关?一个标志,指示文件已准备好进行处理 .

  • 11

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

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

    C语言标准说一个非空的源文件应以换行符结尾,换行符前面不应该有反斜杠字符 . 由于这是一个“shall”子句,我们必须发出违反此规则的诊断消息 . 这在ANSI C 1989标准的2.1.1.2节中 . ISO C 1999标准的5.1.1.2节(也可能是ISO C 1990标准) .

    参考:The GCC/GNU mail archive .

  • 12

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

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

    "No newline at end of file" compiler warning

  • 9

    因为那是how the POSIX standard defines a line

    3.206 Line一个零个或多个非<newline>字符的序列加上一个终止的<newline>字符 .

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

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

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

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

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

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

  • -4

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

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

    确实 - 如果你以一条新线结束:(在理论上)EOL和EOF之间是否有一条空的最后一条线?一个思考......

  • 2

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

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

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

  • 59

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

    printf $'foo\nbar' | while read line
    do
        echo $line
    done
    

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

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

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

  • 0

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

    我们所做的只是:

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

    [{
        someProp: value
    },
    {
        someProp: value
    }] <-- No newline here
    

    该文件是在widows机器中创建的,窗口脚本使用powershall命令处理该文件 . 都好 .

    当我们使用 sed 命令 sed 's|value|newValue|g' foo.txt > foo.txt.tmp 处理相同的文件时,新生成的文件是

    [{
        someProp: value
    },
    {
        someProp: value
    

    由于无效的JSON,它在其余的进程中失败了 .

    因此,使用空的新行结束文件始终是一个好习惯 .

  • 10

    恕我直言,这是个人风格和意见的问题 .

    在过去,我没有把那个新行 . 保存的字符意味着通过14.4K调制解调器提高速度 .

    后来,我把这个换行符放到了使用shift downarrow更容易选择最后一行 .

相关问题