跳到主要内容

换行符转换实战:CRLF 与 LF 互转, 治好跨平台文件的 ^M 乱码

讲清楚 CRLF、LF、CR 三种换行符的来历, 为什么文件在 Windows 和 Linux 之间传一圈就出现 ^M 或全挤成一行, 以及怎样用一次转换统一行尾, 让脚本、Git 和导入流程不再报错。

发布于 作者 李雷
#换行符 #CRLF #LF #跨平台 #文本处理

换行符转换实战:CRLF 与 LF 互转, 治好跨平台文件的 ^M 乱码

一个文本文件里看不见的字符, 往往是最难排查的麻烦。你在 Windows 上写好一个 shell 脚本, 传到 Linux 服务器上一跑, 它报 bad interpreter 或者 command not found, 而你逐字检查脚本, 一个字母都没写错。问题不在你看得见的地方, 而在每行结尾那两个隐藏字符上。

这篇文章把换行符这件事讲透:它到底是什么、为什么跨平台会出问题、怎么一次性把行尾统一干净。

换行符其实是看不见的控制字符

我们按下回车, 屏幕上换了一行, 但文件里存的不是"换行"这个动作, 而是具体的控制字符。常见的有三种:

  • LF(Line Feed, \n, 十六进制 0A):Unix、Linux、macOS 用它, 一个字符表示换行。
  • CRLF(Carriage Return + Line Feed, \r\n, 0D 0A):Windows 用它, 回车加换行两个字符表示一行结束。
  • CR(Carriage Return, \r, 0D):经典 Mac OS 9 及更早的系统用过, 现在很少见, 但旧文件和某些导出工具里还会冒出来。

这个差异是历史遗留。早年的电传打字机要分两步:先让打印头回到行首(回车, CR), 再把纸卷上移一行(换行, LF)。Unix 后来把两步合成一个 LF 了事, Windows 沿用了 DOS 的两字符写法, 于是同一个"换行"在不同系统里存成了不一样的字节。

为什么跨平台传一圈就出现 ^M

最典型的故障长这样。你在 Windows 上有个文件, 每行以 CRLF 结尾。传到 Linux 后, Linux 只认 LF 当换行, 那个多出来的 CR(\r)就被当成普通正文字符留在了每行末尾。在 vimcat -v 里, 这个 CR 会显示成 ^M:

#!/bin/bash^M
echo "deploy"^M

脚本第一行的 #!/bin/bash 后面跟了个 ^M, 系统去找的解释器就变成了 /bin/bash\r 这个根本不存在的路径, 于是报 bad interpreter: No such file or directory

反方向也会出事。一个纯 LF 的文件在老版 Windows 记事本里打开, 因为没有 CR, 记事本不认为那是换行, 整个文件就全挤成一行, 几百行内容糊成一坨。现在的记事本修好了这个问题, 但很多老旧的导入工具、日志解析器、固件烧录软件仍然只认 CRLF。

Git 和脚本最容易踩的坑

我自己最近就被坑过一次。团队里有人用 Windows, 有人用 Mac, 同一个仓库提交几轮之后, git diff 突然显示某个文件"整个改了", 可肉眼看内容明明一模一样。真相是有人的编辑器把 LF 全换成了 CRLF, Git 按字节比对, 每一行都算"变更", 几百行全部标红。代码评审根本没法看, 真正的逻辑改动被淹没在换行噪声里。

这类问题集中在几个地方:

  • Git 仓库:混用 LF 和 CRLF 会制造大量假 diff, 还可能触发 warning: LF will be replaced by CRLF
  • Shell 脚本 / Python 脚本:行尾带 CR 会让 shebang 失效、让字符串末尾多出隐藏字符。
  • 配置文件:.envnginx.conf 这类文件里, 一个尾随 CR 可能让某个值悄悄多带一个不可见字符。
  • CSV / JSONL 导入:解析器按 \n 切行时, 残留的 \r 会污染每条记录的最后一个字段。

一次转换统一行尾

排查这种问题最稳的办法不是逐行删 CR, 而是把整个文件的行尾一次性规范化成同一种。用 文本文件换行转换, 上传文件或直接粘贴内容, 选 LF 还是 CRLF, 复制或下载结果即可。它会把混合的 CRLF、CR、LF 全部统一, 除换行符外不动任何其他文本, 整个过程在浏览器本地完成, 文件不上传。

到底选哪个, 一句话原则:

  • 选 LF:代码、shell 脚本、JSON、Markdown、跑在 Linux/macOS 上的几乎一切, 都用 LF。
  • 选 CRLF:确实要喂给只认 CRLF 的老 Windows 程序, 或者某些必须 CRLF 的批处理文件时, 再用它。

需要提醒的是, 换行转换只处理行尾, 它修不了字符编码问题。如果你看到的是 锟斤拷 这种乱码, 那是 UTF-8 和 GBK 搞混了, 跟换行符无关, 得另外处理编码。

配合其他文本工具一起收尾

把行尾统一只是清理文本的第一步。导入数据前, 文件里常常还堆着重复行。统一好换行之后, 可以接着用 文本去重 把重复条目清掉, 让 CSV 或日志数据干净再进流程。两步做完, 一份在多台机器、多个编辑器之间辗转过的脏文件, 基本就恢复成可放心提交、可放心导入的状态了。

换行符这东西平时谁都不会注意, 直到某个脚本莫名其妙跑不起来, 或者 Git diff 突然炸出几百行红字。记住一个习惯:文件跨系统流转过, 提交或运行之前先把行尾统一一遍, 能省下大半天的排查时间。


Made by Toolora · Updated 2026-06-13