寻找带有BOM的UTF-8文件的优雅方法?

106

出于调试目的,我需要递归搜索一个目录下以UTF-8字节顺序标记(BOM)开头的所有文件。 我当前的解决方案是一个简单的shell脚本:

find -type f |
while read file
do
    if [ "`head -c 3 -- "$file"`" == $'\xef\xbb\xbf' ]
    then
        echo "found BOM in: $file"
    fi
done

或者,如果您更喜欢简短的、难以阅读的单行代码:

find -type f|while read file;do [ "`head -c3 -- "$file"`" == $'\xef\xbb\xbf' ] && echo "found BOM in: $file";done

该功能不能处理包含换行符的文件名,但是这样的文件通常不会出现。

是否有更短或更优雅的解决方案?

是否有任何有趣的文本编辑器或文本编辑器宏?

11个回答

193

这个简单的命令不仅找到了恶心的BOM,还清除了它,怎么样? :)

find . -type f -exec sed '1s/^\xEF\xBB\xBF//' -i {} \;

我喜爱"find" :)

警告上述操作将会对包含这三个字符的二进制文件进行修改

如果您只想显示BOM文件,请使用以下内容:

grep -rl $'\xEF\xBB\xBF' .

10
错误地检测到带有BOM标记的PDF文件... 这是因为它搜索整个文档,而不仅仅是第一行。 - Olivier Refalo
1
或者使用ack命令:"ack '\xEF\xBB\xBF'" - Smar
5
将sed命令修改,使其在第一行前面的“s”之前添加一个“1”,以便它只应用于第一行。 - Ben Combee
33
使用命令 grep -rlI $'\xEF\xBB\xBF' . 来忽略二进制文件。 - dbernard
1
检测和修改JPG和其他二进制文件,正如先前所述。 - Jehy
显示剩余3条评论

45

在Windows上完成此操作的最佳和最简单的方法:

Total Commander → 进入项目的根目录 → 查找文件(Alt + F7)→ 文件类型 *.* → 查找文本 "EF BB BF" → 选择 'Hex' 复选框 → 搜索

然后您会得到列表 :)


7
不错,尤其是使用我长期以来喜欢的Total Commander,但不幸的是它与许多其他搜索工具一样存在一个问题:它会搜索文件中的所有字节,因此会报告许多图片等不相关的结果。可以通过改用正则表达式而非十六进制,并搜索“^\xEF\xBB\xBF”来略微改善情况,这将消除许多图片,但仍然会有一些文件在BOM(字节顺序标记)之后出现(虽然应该很少),当然还会有任何二进制文件偶然在BOM之前具有ASCII换行符号码。在我的测试搜索中,所有图片都已消失。 - Legolas

16
find . -type f -print0 | xargs -0r awk '
    /^\xEF\xBB\xBF/ {print FILENAME}
    {nextfile}'

以上大多数解决方案都会检查文件的第一行之外的更多内容,即使像Marcus的解决方案一样,它们会过滤结果。这个解决方案只测试每个文件的第一行,因此应该会更快一些。


2
在Linux(RHEL6)上,Got正在使用以下命令:find . -type f -print0 | xargs -0 awk '/^\xEF\xBB\xBF/ {print FILENAME} {nextfile}' - Olivier Refalo
我需要如何修改您的代码以修复这些被找到的文件? - Black

9

如果您可以接受一些误报(例如存在非文本文件,或者在文件中间出现ZWNBSP的极小概率情况),您可以使用grep:

fgrep -rl `echo -ne '\xef\xbb\xbf'` .

6
您可以使用grep找到它们,然后使用Perl将其删除,如下所示:
grep -rl $'\xEF\xBB\xBF' . | xargs perl -i -pe 's{\xEF\xBB\xBF}{}'

这个对我有用,被接受的答案没有(我在Mac上)。 - mjsarfatti

5
我会使用类似以下的语句:
grep -orHbm1 "^`echo -ne '\xef\xbb\xbf'`" . | sed '/:0:/!d;s/:0:.*//'

这将确保BOM从文件的第一个字节开始出现。


4

对于 Windows 用户,请参见此处(一个很好的 PHP 脚本,可用于查找项目中的 BOM)。


该链接网站显示:“网站离线,无缓存版本可用”。 - vog
相同的脚本也可在GitHub上找到:http://github.com/emrahgunduz/BomCleaner - emrahgunduz
谢谢伙计,你的答案救了我的一天。 - Krunal Panchal
还有一个BOM查找器:https://github.com/svn2github/wikia/blob/master/extensions/FCKeditor/fckeditor/_dev/php_bom_finder.php(如果有人不喜欢“自动”清理,或者只想查找带有BOM的文件) - meloniq

3

我仅使用此功能来纠正JavaScript文件:

find . -iname *.js -type f -exec sed 's/^\xEF\xBB\xBF//' -i.bak {} \; -exec rm {}.bak \;

3

解决这个问题的过度方案是phptags(不是同名的vi工具),它专门查找PHP脚本:

phptags --warn ./

将输出类似于:

./invalid.php: TRAILING whitespace ("?>\n")
./invalid.php: UTF-8 BOM alone ("\xEF\xBB\xBF")

--whitespace模式将自动修复此类问题(递归,但断言仅重写.php脚本。)


2
find -type f -print0 | xargs -0 grep -l `printf '^\xef\xbb\xbf'` | sed 's/^/found BOM in: /'
  • find -print0会在每个文件名之间放置一个null \0,而不是使用新行。
  • xargs -0期望使用null分隔的参数,而不是使用换行符分隔。
  • grep -l列出与正则表达式匹配的文件。
  • 正则表达式^\xeff\xbb\xbf并不完全正确,因为它将匹配非BOM UTF-8文件,如果它们在行首有零宽度空格。

1
在使用grep之前,管道中仍需要一个“head 1”。 - MSalters

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接