公众号旧文
为什么 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:换行(我只关心发生了什么)
扩展阅读: