最稳的清除 utf-8 bom 命令是 sed -i '1s/^\xef\xbb\xbf//' file.xml,仅首行匹配删除,需确认编码并注意系统 sed 差异;iconv -f utf-8 -t utf-8//ignore 更适合批量转码去 bom;python 推荐用 encoding="utf-8-sig" 自动跳过 bom。

Linux 下用 sed 一键清除 UTF-8 BOM
直接上最稳的命令:sed -i '1s/^\xEF\xBB\xBF//' file.xml。它只在第一行开头匹配并删除 UTF-8 BOM(\xEF\xBB\xBF),不影响其他内容。注意必须加 -i 才能原地修改,否则只是输出到终端。
常见错误是写成 sed -i 's/^\xEF\xBB\xBF//' file.xml(漏了 1),这会让 sed 每行都扫描,虽然 BOM 只可能在首行,但多扫会拖慢大文件处理速度;更糟的是某些老版本 sed(如 macOS 自带)根本不支持十六进制转义,会静默失败——务必先用 xxd file.xml | head -n 1 确认开头确实是 ef bb bf。
- 只对真实含 BOM 的文件生效,无害;但若文件没 BOM,该命令也不报错,容易误以为“已处理”
- 不适用于 Windows 行尾(
\r\n)混在 BOM 后的边界情况,此时 BOM 实际是\xEF\xBB\xBF\r\n,需改用sed -i '1s/^\xEF\xBB\xBF\r\?//' file.xml -
sed -i在不同系统行为不一致:GNU sed(Linux)允许空备份后缀,BSD sed(macOS)要求显式写-i ''
用 iconv 转码时顺手剥离 BOM
如果 XML 原本编码混乱,或你本来就要转 UTF-8,iconv 是更干净的选择:iconv -f UTF-8 -t UTF-8//IGNORE file.xml > clean.xml。关键在 //IGNORE 后缀——它让 iconv 跳过非法字节,而 BOM 在 UTF-8 中不是必需字节,多数实现会直接丢弃。
但别用 //TRANSLIT 或省略后缀,前者可能把 BOM 当乱码替换为 ?,后者遇到 BOM 会报错退出。这个方法适合批量处理,配合 find . -name "*.xml" -exec iconv ... \; 很顺,但要注意 iconv 不支持原地编辑,必须重定向输出。
-
UTF-8//IGNORE对纯 ASCII 文件也安全,不会改动内容 - 某些嵌入式系统或旧版
iconv不支持//IGNORE,会提示 “Unknown mode”,此时退回sed方案 - 如果文件实际是 UTF-16 或 GBK,先用
file -i file.xml确认编码,再设对-f参数,否则转出来全是乱码
Python 脚本处理时绕开 BOM 的惯用法
用 Python 解析 XML 时,xml.etree.ElementTree.parse() 遇到 BOM 通常会抛 ParseError: not well-formed (invalid token)。根本解法不是删 BOM,而是打开文件时指定 encoding="utf-8-sig":with open("file.xml", encoding="utf-8-sig") as f: tree = ET.parse(f)。
utf-8-sig 是 Python 的特殊编码名,它自动识别并跳过 BOM,后续读取全部按标准 UTF-8 处理。比手动 strip 更可靠,因为不用关心 BOM 是否真存在、是否跨行、是否被压缩工具损坏。
- 仅对文本模式打开有效,二进制模式(
open(..., "rb"))下该参数无效 - Python 3.4+ 支持,旧版本需手动检测:
content = f.read(); content.lstrip("\ufeff") - 别在写入时用
utf-8-sig,否则每次保存都会额外加 BOM,XML 标准不推荐带 BOM
为什么 XML 规范不欢迎 BOM
XML 1.0 明确规定:BOM 是可选的字节序列,解析器必须能处理它,但“不鼓励使用”。真实痛点在于:很多 XML 工具链(如 Java 的 DocumentBuilder、某些 C++ SAX 解析器)把 BOM 当作非法字符,直接中断解析;HTTP 传输中,BOM 还可能干扰 Content-Type 的 charset 检测,导致浏览器或服务端误判编码。
所以生产环境 XML 最好从源头禁用 BOM——编辑器保存时选 “UTF-8 without BOM”,CI 流水线里加个检查脚本:grep -l $'\xEF\xBB\xBF' *.xml,有输出就立刻 fail。别等上线后被某个冷门解析器卡住。
BOM 的存在本身不破坏数据,但它像一个隐形的兼容性雷区,扫清它不难,但得知道在哪踩、怎么踩才不炸自己。










