公众号旧文

为什么 Win/Linux/Mac 的换行符不一样?

作者:胖子阅读 —

如果你在不同操作系统之间来回拷贝过文件,

你大概率曾遇到过这种诡异情况:

在 Linux 里打开一个从 Windows 拷贝来的文本,行尾多出一堆 ^M;

把 Linux 的文件丢到某些 Windows 工具里,整篇多段内容却挤成一行。

相信你第一次看到,会不禁感叹:

这也太离谱了,连换行这么基础的东西都统一不了?

但真相是,它们不是不统一,而是来自三个不同的世界。

一、换行,原本就不是一个动作

在上篇文章为什么Enter是进入,但Enter键却叫回车?中,

我提到了,在计算机出现之前,人们用的是打字机。

打字机里有个关键结构叫“字车”,每打一个字,它就往右移动一格。

一行打满之后,你必须手动完成两个动作:

把字车推回最左边(Carriage Return,简称 CR) 让纸往上滚一行(Line Feed,简称 LF)

这两个动作是分开的。

于是,在后来计算机继承打字机概念时,就留下了两个控制字符:

  • \\r:回车(CR)
  • \\n:换行(LF)

而这,就是所有问题的源头。

二、三种系统,三种选择

当操作系统开始设计文本格式时,它们面对同一个问题:

换行到底要不要分成两个动作?

不同系统,给出了完全不同的答案。

1、Windows:我全都要

Microsoft 的 Windows 选择了最保守的方案:

完整保留打字机逻辑

也就是说,一个换行必须是:

\r\n

先回车,再换行,一个都不能少。

2、Unix / Linux:只要结果就够了

以 Linux 为代表的 Unix 系统,走的是另一条路:

只保留换行这个结果。

因为在屏幕上换到下一行,本来就会从行首开始写。

于是 Unix 直接砍掉了 CR,只保留:

\n

逻辑是:你不需要告诉我怎么移动,只需要告诉我换行了。

3、Mac(旧系统):只用回车

Apple 在早期的 Classic Mac OS 中,走了第三条路线:

只用 CR(\\r)

也就是说,它只关心回到行首,至于换到下一行,由系统自己处理。

不过需要注意,现代 macOS 已经完全采用 Unix 方案(\\n)

三、为什么到现在还没统一?

如果是今天才开始设计,统一用

\n

就好了。

但问题在于,历史已经写进文件里了。

几十年来,已经有海量文本文件被保存成:

  • Windows:\\r\\n
  • Linux:\\n
  • 老 Mac:`\r```

如果强行统一,那么所有旧文件都会解析错误。

这在操作系统层面是不可接受的。

于是,三种格式就这样一直共存了下来。

四、你看到的那些怪现象,其实都有原因

比如你在 Linux 里看到的:

hello^M
world^M

那个 ^M,其实就是 \\r 被显示出来了。

因为 Linux 只认 \\n,多出来的 \\r 就变成了可见字符。

反过来,如果某些 Windows 工具只认 \\r\\n,遇到只有 \\n 的文件,就会认为这根本没换行,于是整篇内容挤在一起。

五、后来人是怎么补救的?

现实世界不会要求用户理解这些细节,于是各种工具开始帮你兜底。

比如:

dos2unix file.txt
unix2dos file.txt

再比如 Git:

git config --global core.autocrlf true

它会在不同系统之间自动转换换行符,让你几乎感觉不到差异的存在。

六、问题的本质到底是什么?

很多人把这个问题当成兼容性问题,但它更像是一个哲学问题。

Windows 记录的是动作 Linux 记录的是结果

  • Windows:回车 + 换行(我告诉你怎么做)
  • Linux:换行(我只关心发生了什么)

扩展阅读:


30 年网龄,却在今天才搞懂 SwitchyOmega

域名挂了之后,如何把网站迁移到新域名?

互联网是怎么从 IPv4 无缝过渡到 IPv6 的?

如何在 macOS 上创建 TXT 文本文档?