如何从UTF-8文件中删除BOM?


63

我有一个带有BOM的UTF-8编码文件,并且想要删除BOM。是否有任何Linux命令行工具可从文件中删除BOM?

$ file test.xml
test.xml:  XML 1.0 document, UTF-8 Unicode (with BOM) text, with very long lines


1
几个月前,我已经做了一个非常简单的工具:oskog97.com/read/?path=/small-scripts/killbom&referer = / ...如果在/ usr / local / bin中安装类似的东西,可能值得您有许多带有BOM的UTF-8编码文件。
奥斯卡·斯科格

Answers:


76

如果不确定文件是否包含UTF-8 BOM,则此操作(假设使用GNU实现sed)将删除BOM(如果存在),否则将不进行任何更改。

sed '1s/^\xEF\xBB\xBF//' < orig.txt > new.txt

您还可以使用以下-i选项覆盖现有文件:

sed -i '1s/^\xEF\xBB\xBF//' orig.txt

4
这在utf8语言环境中可能不起作用,但是在c或posix之前添加语言环境覆盖将始终有效。
hildred '17

3
@hildred我已经在en_US.UTF-8语言环境中对其进行了测试,并且可以正常工作。什么时候会失败?
m13r

2
@ m13r,这取决于sed和compile选项的版本。在失败的情况下,具有Unicode字符类的sed的非常新版本将把三个字节的序列作为单个字符引入,这与三个字符的序列不匹配。但是,在这种情况下,您可以进行16位字符匹配。但是,这是一个新功能,并不普遍存在。如果要测试,建议编译最新版本。
hildred '17

4
要修复它以使其与启用unicode的sed一起工作,请执行LC_ALL = C sed'1s / ^ \ xEF \ xBB \ xBF //
Joshua

@CSM很好,但是在一种特殊情况下不起作用:Bevore:-<U+FEFF>\chapter{xxx}After:+\chapter{xxx}^M 说明:在乳胶文件中使用MS字输入错字。Linux下的Latex显示了提到的错误。输出来自git系统。我如何也可以更改表达式以适应这种特殊情况?
Cutton Eye

64

在UTF-8中,BOM没有意义。这些通常是由Microsoft操作系统上的虚假软件错误地添加的。

dos2unix 会删除它,并注意Windows文本文件的其他特性。

dos2unix test.xml

17
我同意UTF-8编码的BOM没有意义,但不管您相信与否,很多人认为这是一个有助于将UTF-8与其他8位编码区分开的好主意。因此,这是一个品味问题。Windows记事本是故意添加的BOM。
JohanMyréen'17

17
如果上下文只是有关如何删除它的问题,那么是否有意义又有什么关系呢?根据Wikipedia的介绍,记事本要求BOM将该文件识别为UTF-8,并且Google Docs在将文件导出为文本时也会添加该文件。我怀疑他们全都做错了
ilkkachu

评论不作进一步讨论;此对话已转移至聊天
terdon

1
有没有一种方法不转换行尾而只删除BOM表dos2unix
m13r

2
@ m13r然后在此答案中使用sed脚本。这将仅删除物料清单(如果存在),则不会进行其他任何更改。
箭头

25

可以使用以下tail命令从文件中删除BOM :

tail -c +4 withBOM.txt > withoutBOM.txt

2
为什么是4?BOM有3个字节。
deviantfan '17

10
@deviantfan这就是为什么要跳过第4个字节的原因。
斯特凡Chazelas

9
tail使用基于1的索引?WTF!
CodesInChaos

5
@CodesInChaos tail -c -1tail -c 1tail通常用于)是从最后一个字节tail -c +1开始,从第一个字节开始的内容。tail -c 0/ tail -c +0因为这样会更加不直观。
斯特凡Chazelas

2
@deviantfan :(dd bs=1 count=3 of=/dev/null; cat) <input >output。或使用(head -c3 >/dev/null; cat)GNU-即使在UTF8或其他非单字节语言环境中;GNU head执行'char'= byte。
dave_thompson_085

20

使用VIM

  1. 在VIM中打开文件:

    vi text.xml
    
  2. 删除BOM编码:

    :set nobomb
    
  3. 保存并退出:

    :wq
    

奇怪的是,在Mac上使用vim 8时,我有一个Excel制作的csv utf-8文件,它以开头<feff>,但:set nobomb没有修改或删除它。
dlamblin

5

您可以使用

LANG=C LC_ALL=C sed -e 's/\r$// ; 1 s/^\xef\xbb\xbf//' -i -- filename

从文件的开头删除字节顺序标记(如果有的话),以及将任何CR LF换行符仅转换为LF。该LANG=C LC_ALL=C命令告诉外壳程序您希望命令在默认C语言环境(也称为默认POSIX语言环境)中运行,在该语言环境中,构成字节顺序标记的三个字节被视为字节。在-i对sed的选项意味着原地。如果使用-i.old,则sed将原始文件另存为filename.old,将新文件(如果有修改,另存为)另存为filename


我个人喜欢这样~/bin/fix-ms; 例如,作为

#!/bin/dash
export LANG=C LC_ALL=C
if [ $# -gt 0 ]; then
    for FILE in "$@" ; do
        sed -e 's/\r$// ; 1 s/^\xef\xbb\xbf//' -i -- "$FILE" || exit 1
    done
else
    exec sed -e 's/\r$// ; 1 s/^\xef\xbb\xbf//'
fi

因此,如果我需要使用它来说明所有C源文件和标头(例如,我的MS-DOS时代的旧代码!),我只需运行

find . -name '*.[CHch]' -print0 | xargs -r0 ~/bin/ms-fix

或者,如果我只想查看这样的文件,而无需修改它,则可以运行

~/bin/ms-fix < filename | less

<U+FEFF>在我的UTF-8终端上看不到丑陋的东西。


为什么不简单sed -e 's/\r$// ; 1 s/^\xef\xbb\xbf//' -i -- "$@"
斯特凡Chazelas

@StéphaneChazelas:因为如果替换出现问题,我希望脚本立即退出,但sed -e 's/\r$// ; 1 s/^\xef\xbb\xbf//' -i -- "$@"不会发生;它确实返回退出代码,但是在退出之前,它会处理参数列表中列出的所有文件。
标称动物

@StéphaneChazelas:--文件名之前的当然很重要:如果没有它,则sed可能会将以短划线开头的文件名视为选项。我将这些内容编辑成答案;谢谢你的提醒!
名义动物

0

最近,我发现了这个小巧的命令行工具,该工具可在任意UTF-8编码文件上添加或删除BOM:UTF BOM Utils(github上的新链接

几乎没有什么缺点,您只能下载纯C ++源代码。您必须创建makefile(例如,使用CMake)并自己进行编译,此页面上未提供二进制文件。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.