我有一个使用BOM表以UTF-8编码的文件,并且想要删除BOM表。是否有任何Linux命令行工具可从文件中删除物料清单?

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


评论

相似:具有BOM的AWK:是否有任何很酷的方法通过正则表达式处理Unicode BOM?

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

奇怪的是,交叉发布在stackoverflow.com/questions/45240387/…

#1 楼

如果不确定文件是否包含UTF-8 BOM表,则此操作(假设sed的GNU实现)将删除BOM表(如果存在),否则将不进行任何更改。 />
sed '1s/^\xEF\xBB\xBF//' < orig.txt > new.txt


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

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


如果使用的是BSD版本的sed(例如macOS),那么您需要让bash转义:

 sed $'1s/\xef\xbb\xbf//' < orig.txt > new.txt


评论


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

–躲藏
17年7月23日在15:29

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

– m13r
17年7月24日在6:55



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

–躲藏
17年7月24日在16:25



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

–约书亚
17年7月24日在17:41

@ mazunki,1s /表示仅搜索第一行;其他行不受影响。 ^表示仅在(第一)行的开头匹配。 \ xEF \ xBB \ xBF是UTF-8 BOM(转义的十六进制字符串)。 //表示不作任何替换。我可以在末尾添加1(表示1s / ^ xEF \ xBB \ xBF // 1),这意味着仅匹配该行上第一次出现的模式。但是,由于搜索使用^锚定,因此没有任何区别。如果文件在第一行的开头没有BOM,则该模式将不匹配,因此不会进行任何更改。

– CSM
19-10-27在18:47



#2 楼

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

评论


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

– JohanMyréen
17年7月23日在14:02

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

–ilkkachu
17年7月23日在14:09

有没有一种方法不转换行尾,而只使用dos2unix删除BOM?

– m13r
17年7月25日在7:55



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

–艾萨克
17年7月26日在5:51

@JohanMyréen是的,但称它们为UTF-8是不正确的。它们不是UTF-8文件。它们是带有BOM的UTF-8文件,这是另一种文件格式。我想那些Windows怪胎会不满意被称为MSOffice文件的ODT文件:)

– 9ilsdx 9rvj 0lo
18年11月9日在9:47

#3 楼

使用VIM


在VIM中打开文件:
 vi text.xml



删除BOM表编码:
 :set nobomb



保存并退出:
 :wq




对于非交互式解决方案,请尝试以下命令行:
< preclass =“ lang-bsh prettyprint-override”> vi -c ":set nobomb" -c ":wq" text.xml
应从命令行删除BOM,保存文件并退出。

评论


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

– dlamblin
19-10-9在21:11

这比在大型文件上拖尾要快得多。

–user239558
19/12/2在20:14

#4 楼

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

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


评论


为什么是4? BOM有3个字节。

–deviantfan
17年7月23日在17:12

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

–StéphaneChazelas
17年7月23日在18:33

尾部是否使用基于1的索引? WTF!

– CodesInChaos
17年7月23日在19:31



@ CodesInChaos,tail -c -1或tail -c 1(通常用于tail)是从最后一个字节开始的内容,tail -c +1从第一个字节开始。 tail -c 0 / tail -c +0会更不直观。

–StéphaneChazelas
17年7月23日在23:05

@deviantfan:(dd bs = 1 count = 3 of = / dev / null; cat)<输入>输出。或使用GNU(头-c3> / dev / null; cat)-即使在UTF8或其他非单字节语言环境中也是如此; GNU head执行'char'= byte。

–dave_thompson_085
17年7月24日在6:16

#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语言环境)中运行,其中构成字节顺序标记的三个字节被视为字节。 sed的-i选项表示就地。如果使用-i.old,那么sed将原始文件另存为filename.old,并将新文件(如果有修改,另存为)另存为filename。例如,作为

#!/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


,在我的UTF-8终端上看不到难看的~/bin/fix-ms

评论


为什么不简单地sed -e's / \ r $ //; 1 s / ^ \ xef \ xbb \ xbf //'-i-“ $ @”?

–StéphaneChazelas
17年7月24日在14:02

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

–动物
17年7月24日在14:24



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

–动物
17年7月24日在14:27

#6 楼

我在常规上使用vim一线纸:

vim --clean -c 'se nobomb|wq' filename

vim --clean -c 'bufdo se nobomb|wqa' filename1 filename2 ...


评论


使用VIM的前个性也应该可以实现这一点。

– JdeBP
20-10-7在9:46

#7 楼

我有一个略有不同的问题,正把它放在这里给像我一样,最终在这里得到充满ZERO WIDTH NO-BREAK SPACE个字符的数据(当它们是文件的第一个字符时被称为Byte Order Mark)的人。通过复制出grafana查询指标字段来获取此数据,并且它在一行中有多个(17)\xef\xbb\xbf序列(在vim中显示为rate<feff>(<feff>node<feff>{<feff>job<feff>),只有81个实际字符。略微:
LANG=C LC_ALL=C sed -e 's/\xef\xbb\xbf//g'

,而:set nobomb中的vim只会删除文件中的第一个。
尝试过: ,但它们仍然在那里(即使在写完之后...)

#8 楼

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

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