CRLF 为什么会弄坏脚本
Windows 文本文件的行尾是 CR+LF 两个字节,Linux 只认 LF。脚本或配置里混进 CR 之后,典型表现是执行时报 bad interpreter: No such file or directory(shebang 行尾多了个 CR),或者报出莫名的语法错误。文本类文件从 Windows 迁到 Linux 后统一转一次换行符,是迁移收尾的固定动作。
基本信息
| 适用场景 | Windows 编辑过的脚本、配置文件、systemd 单元迁到 Linux |
|---|---|
| 转换工具 | dos2unix 与 unix2dos 成对使用 |
| 批量方式 | find 配合 xargs -0 或 -print0 处理 |
| 验证方式 | file 命令输出中不应再出现 CRLF 字样 |
| 处理顺序 | 先确认并转编码,再转换行符 |
典型使用场景
- 从 Windows 打包过来的部署脚本在 Linux 上执行报错
- systemd 单元或 crontab 行里带 CR 导致服务起不来
- 批量迁移后统一清理文本文件的换行符
- 排查「同一份脚本同事能跑我不能跑」的差异
- 转换前先判断文件编码,避免 GBK 与 UTF-8 混用
转换与验证
转换与验证
file /opt/app/bin/start.sh # 输出含 CRLF line terminators 即为 DOS 换行
file -i /opt/app/bin/start.sh # 先看字符集,GBK 文本要先用 iconv 转 UTF-8
dos2unix /opt/app/bin/start.sh # 单文件转换(RHEL 系先 dnf install dos2unix)
find /opt/app -type f -name '*.sh' -print0 | xargs -0 dos2unix # 只处理脚本类文本
sed -i 's/\r$//' /etc/systemd/system/app-web.service # 无 dos2unix 时的备选
# vim 内查看与转换::set ff? 显示 dos 时执行 :set ff=unix 后保存
file /opt/app/bin/start.sh # 转换后复核,不应再有 CRLF
grep -rl $'\r' /etc/systemd/system/ 2>/dev/null | head # 抽查残留的 CR现象与成因对照
| 现象 | 成因 | 确认方式 |
|---|---|---|
| bad interpreter | shebang 行尾多了 CR | file 查看或 vim 里 :set ff? |
| syntax error near unexpected token | 脚本中混入 CR 字符 | grep 搜索 CR 或用 file 判断 |
| 单元文件无法解析 | unit 文件含 CR | systemd-analyze verify 报行号定位 |
| 同一脚本表现不同 | 一方转换过另一方没有 | 对比 file 输出与仓库行尾设置 |
处理顺序很重要:文件编码(GBK 转 UTF-8)要先于换行符转换;顺序颠倒会把 CR 混进新编码里,制造出更难查的乱码问题。
批量转换必须限定文本类型(*.sh、*.conf、*.service 等):对二进制文件执行 dos2unix 会直接破坏文件,且未必能恢复。
治本的做法是把行尾统一前置到开发环节:在仓库中配置换行符策略,让提交到版本库的文本文件保持 LF,迁移时就不必每次靠事后转换补救。