使用awk删除字节顺序标记


105

awk用于删除BOM的脚本(大概是单行)会是什么样子?

规范:

  • 在第一个(NR > 1)之后打印每一行
  • 第一行:如果以#FE #FF或开头#FF #FE,请删除并打印其余

Answers:


114

试试这个:

awk 'NR==1{sub(/^\xef\xbb\xbf/,"")}{print}' INFILE > OUTFILE

在第一条记录(行)上,删除BOM表字符。打印每条记录。

或更短一点,使用以下知识:awk中的默认操作是打印记录:

awk 'NR==1{sub(/^\xef\xbb\xbf/,"")}1' INFILE > OUTFILE

1 是最短的条件,总是求值为true,因此将打印每条记录。

请享用!

-附录-

Unicode字节顺序标记(BOM)常见问题解答包含下表,列出了每种编码的确切BOM字节:

Bytes         |  Encoding Form
--------------------------------------
00 00 FE FF   |  UTF-32, big-endian
FF FE 00 00   |  UTF-32, little-endian
FE FF         |  UTF-16, big-endian
FF FE         |  UTF-16, little-endian
EF BB BF      |  UTF-8

因此,您可以从上表中看到\xef\xbb\xbfEF BB BF UTF-8BOM表字节的对应关系。


1
子语句中间的点似乎太多了(至少我的awk抱怨了这一点)。除此之外,这正是我搜索的内容,谢谢!
Boldewyn

5
但是,此解决方案适用于UTF-8编码的文件。对于其他
格式

2
所以:awk '{if(NR==1)sub(/^\xef\xbb\xbf/,"");print}' INFILE > OUTFILE并确保INFILE和OUTFILE不同!
史蒂夫·克莱

1
如果使用过perl -i.orig -pe 's/^\x{FFFE}//' badfile,则可以依靠PERL_UNICODE和/或PERLIO变量进行编码。PERL_UNICODE = SD适用于UTF-8;对于其他人,则需要PERLIO。
tchrist 2011年

1
也许是短一些的版本:awk 'NR==1{sub(/^\xef\xbb\xbf/,"")}1'
TrueY

122

使用GNU sed(在Linux或Cygwin上):

# Removing BOM from all text files in current directory:
sed -i '1 s/^\xef\xbb\xbf//' *.txt

在FreeBSD上:

sed -i .bak '1 s/^\xef\xbb\xbf//' *.txt

使用GNU或FreeBSD的优点sed:该-i参数的意思是“就地”,并且将更新文件而无需重定向或奇怪的技巧。

在Mac上:

awk解决方案在另一个答案中有效,但是sed上面的命令不起作用。至少在Mac(Sierra)sed文档中没有提到支持十六进制转义ala \xef

任何程序都可以通过spongemoreutils传递到该工具来实现类似的技巧:

awk '…' INFILE | sponge INFILE

5
我在Mac OS X上精确地尝试了第二个命令,结果是“成功”,但是实际上并没有发生替换。
Trejkaz

1
值得注意的是,这些命令替换了一个特定的字节序列,这是可能的字节顺序标记之一。也许您的文件具有不同的BOM序列。(我没有其他帮助,因为我没有Mac)
DenilsonSáMaia

3
当我在OS X上使用0xef 0xbb 0xbf作为BOM的文件上尝试第二条命令时,它实际上并未进行替换。
John Wiseman

在OSX中,我只能通过perl使其工作,如下所示:stackoverflow.com/a/9101056/2063546
Ian

在OS X El Capitan上10.11.6,这不起作用,但是官方答案stackoverflow.com/a/1068700/9636可以正常工作。
Heath Borders

42

不是awk,但是更简单:

tail -c +4 UTF8 > UTF8.nobom

要检查BOM:

hd -n 3 UTF8

如果存在BOM,您将看到: 00000000 ef bb bf ...


6
对于UTF-16,BOM是2字节,对于UTF-32,BOM是4字节,当然,最初没有业务在UTF-8中。
tchrist 2011年

2
@KarolyHorvath是的,确切地说。不建议使用它。它打破了东西。编码应由更高级别的协议指定。
tchrist 2012年

1
@tchrist:您的意思是说它打破了破碎的东西?:)适当的应用程序应该能够处理该BOM。
Karoly Horvath'3

7
@KarolyHorvath我的意思是它破坏了很多程序。那不是我说的吗 当您以UTF-16或UTF-32编码打开流时,解码器知道不计算BOM。使用UTF-8时,解码器将BOM表显示为数据。这是无数程序中的语法错误。即使是Java的解码器,其行为也是如此,通过设计!UTF-8文件上的BOM放错了位置并且很麻烦:它们是错误的!他们打破了很多东西。甚至只是cat file1.utf8 file2.utf8 file3.utf3 > allfiles.utf8会被打破。切勿在UTF-8上使用BOM。期。
tchrist 2012年

6
hd不适用于OS X(截至10.8.2),所以检查的UTF-8 BOM那里,你可以使用以下命令:head -c 3 file | od -t x1
mklement0 2012年

21

除了将CRLF行尾转换为LF之外,dos2unix还删除BOM表:

dos2unix *.txt

dos2unix 还将带有BOM的UTF-16文件(而不是没有BOM的UTF-16文件)转换为没有BOM的UTF-8:

$ printf '\ufeffä\n'|iconv -f utf-8 -t utf-16be>bom-utf16be
$ printf '\ufeffä\n'|iconv -f utf-8 -t utf-16le>bom-utf16le
$ printf '\ufeffä\n'>bom-utf8
$ printf 'ä\n'|iconv -f utf-8 -t utf-16be>utf16be
$ printf 'ä\n'|iconv -f utf-8 -t utf-16le>utf16le
$ printf 'ä\n'>utf8
$ for f in *;do printf '%11s %s\n' $f $(xxd -p $f);done
bom-utf16be feff00e4000a
bom-utf16le fffee4000a00
   bom-utf8 efbbbfc3a40a
    utf16be 00e4000a
    utf16le e4000a00
       utf8 c3a40a
$ dos2unix -q *
$ for f in *;do printf '%11s %s\n' $f $(xxd -p $f);done
bom-utf16be c3a40a
bom-utf16le c3a40a
   bom-utf8 c3a40a
    utf16be 00e4000a
    utf16le e4000a00
       utf8 c3a40a

3

我知道这个问题是针对unix / linux的,我认为值得一提的是unix受到挑战的一个好选择(在Windows上,带有UI)。
我在一个WordPress项目上遇到了同样的问题(BOM导致rss feed和页面验证出现问题),我不得不查看一个很大的目录树中的所有文件,以找到BOM表中的所有文件。在其中找到一个名为“ 替换先锋”的应用程序:

批处理运行器->搜索(在子文件夹中查找所有文件)->替换模板->二进制删除BOM(为此,有一个现成的搜索和替换模板)。

这不是最优雅的解决方案,它确实需要安装程序,这是一个缺点。但是,一旦我发现周围发生的事情,它就像一个咒语一样工作(从大约2300个BOM中找到了3个文件)。


1
当我找到您的解决方案时,我感到非常高兴,但是我没有特权在公司计算机上安装软件。今天花了很多时间,直到我找到了替代方案:将Notepad ++与PythonScript plugin一起使用。 superuser.com/questions/418515/…还是谢谢!
2015年
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.