你有没有遇到过这样的情况:明明在本地测试好好的脚本,推送到服务器后突然报错?或者同事打开你写的配置文件,发现每一行都莫名其妙地连在一起?问题很可能就出在“换行符”这个不起眼的细节上。
换行符不是统一的
很多人以为按下回车产生的“换行”在所有系统里都一样,其实不然。不同的操作系统使用不同的换行编码标准:
- Windows 使用 CRLF(\r\n,即回车+换行)
- Linux 和 macOS(现代版本)使用 LF(\n,仅换行)
- 老版 macOS(9 及之前)曾用 CR(\r,仅回车)
这些字符在文本编辑器里通常不可见,但程序会严格解析。比如一个在 Windows 上生成的 shell 脚本,如果换行符是 CRLF,拿到 Linux 环境执行时,解释器可能识别不了 \r,导致命令找不到,报错类似 command not found: \r。
Git 项目中的典型坑
团队协作中,开发者分布在不同操作系统,这个问题更明显。你在 Mac 上写了个 JSON 配置文件,提交到仓库,同事在 Windows 上拉下来,Git 自动把 LF 转成了 CRLF。他再改点内容提交,又可能转回去。来回几次,diff 里全是整行变更,根本看不出实际改了啥。
Git 提供了 core.autocrlf 设置来缓解:
# Windows 用户
git config --global core.autocrlf true
# Mac/Linux 用户
git config --global core.autocrlf input
设置为 input 时,提交时自动转成 LF,检出时不转换,适合类 Unix 系统。而 true 表示检出时转成 CRLF,提交时转回 LF。
如何查看和转换换行符
用 cat -A 可以看清换行符真相:
cat -A script.sh
输出中,$ 代表 LF,^M$ 代表 CRLF。如果你看到一堆 ^M,基本可以确定是 Windows 风格换行符混入了 Unix 环境。
批量转换可以用 dos2unix 或 sed:
dos2unix broken-script.sh
# 或者
sed -i 's/\r$//' problematic-file.txt
统一标准才是长久之计
最好的办法是在项目初期就定下换行编码标准。现在很多项目根目录放个 .editorconfig 文件,明确指定:
root = true
[*.sh]
end_of_line = lf
[*.json]
end_of_line = lf
主流编辑器都支持 .editorconfig,能自动按规则保存文件。配合 CI 流程做换行符检查,能提前拦截问题。
别小看这一两个字符的差异,它们能在你毫无防备的时候,让自动化脚本全线崩溃。早一点关注换行编码标准,少走很多弯路。