【问题标题】:Using awk to remove the Byte-order mark使用 awk 去除字节顺序标记
【发布时间】:2010-11-07 07:22:03
【问题描述】:

用于删除 BOMawk 脚本(可能是单行)会是什么样子?

规格:

  • 打印第一行之后的每一行 (NR > 1)
  • 对于第一行:如果它以 #FE #FF#FF #FE 开头,请删除这些并打印其余部分

【问题讨论】:

    标签: unicode awk byte-order-mark


    【解决方案1】:

    使用 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 上:

    This awk solution in another answer works,但上面的sed 命令不起作用。至少在 Mac (Sierra) sed 文档上没有提到支持十六进制转义ala \xef

    通过从moreutils 管道到sponge 工具,任何程序都可以实现类似的技巧:

    awk '…' INFILE | sponge INFILE
    

    【讨论】:

    • 我在 Mac OS X 上精确地尝试了第二个命令,结果是“成功”,但实际上并没有发生替换。
    • 值得注意的是,这些命令替换了一个特定的字节序列,即one of the possible byte-order-marks。也许您的文件有不同的 BOM 序列。 (除此之外我无能为力,因为我没有 Mac)
    • 当我在 OS X 上对使用 0xef 0xbb 0xbf 作为 BOM 的文件尝试第二个命令时,它实际上并没有进行替换。
    • 在 OSX 中,我只能通过 perl 让它工作,如下所示:stackoverflow.com/a/9101056/2063546
    • 在 OS X El Capitan 10.11.6 上,这不起作用,但官方回答 stackoverflow.com/a/1068700/9636 工作正常。
    【解决方案2】:

    试试这个:

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

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

    或者稍微短一些,使用 awk 中的默认操作是打印记录的知识:

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

    1 是始终评估为真的最短条件,因此会打印每条记录。

    享受吧!

    -- 附录--

    Unicode Byte Order Mark (BOM) FAQ 包括下表,列出了每种编码的确切 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-8 BOM 字节的对应关系。

    【讨论】:

    • 看来sub语句中间的点太多了(至少,我的awk抱怨过)。除此之外,这正是我搜索的内容,谢谢!
    • 但是,此解决方案适用于 UTF-8 编码文件。对于其他,如 UTF-16,请参阅 Wikipedia 以获取相应的 BOM 表示:en.wikipedia.org/wiki/Byte_order_mark
    • 所以:awk '{if(NR==1)sub(/^\xef\xbb\xbf/,"");print}' INFILE > OUTFILE 并确保 INFILE 和 OUTFILE 不同!
    • 如果您使用perl -i.orig -pe 's/^\x{FFFE}//' badfile,您可以依靠您的 PERL_UNICODE 和/或 PERLIO 变量进行编码。 PERL_UNICODE=SD 适用于 UTF-8;对于其他人,您需要 PERLIO。
    • 也许有点短版本:awk 'NR==1{sub(/^\xef\xbb\xbf/,"")}1'
    【解决方案3】:

    不是 awk,而是更简单:

    tail -c +4 UTF8 > UTF8.nobom
    

    要检查 BOM:

    hd -n 3 UTF8
    

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

    【讨论】:

    • BOM 对于 UTF-16 来说是 2 字节,对于 UTF-32 来说是 4 字节,当然,首先在 UTF-8 中没有任何业务。
    • @KarolyHorvath 是的,准确地说。不推荐使用它。它打破了东西。编码应该由更高级别的协议指定。
    • @tchrist:你的意思是它破坏了破碎的东西? :) 适当的应用程序应该能够处理该 BOM。
    • @KarolyHorvath 我的意思是它破坏了很多程序。这不是我说的吗?当您以 UTF-16 或 UTF-32 编码打开流时,解码器知道不计算 BOM。当您使用 UTF-8 时,解码器将 BOM 呈现为数据。这是无数程序中的语法错误。 Even Java’s decoder behaves this way, BY DESIGN! UTF-8 文件上的 BOM 放错了位置,让人头疼:它们是一个错误!它们破坏了很多东西。即使只是cat file1.utf8 file2.utf8 file3.utf3 > allfiles.utf8 也会被破坏。切勿在 UTF-8 上使用 BOM。期间。
    • hd 在 OS X 上不可用(从 10.8.2 开始),因此要检查 UTF-8 BOM,您可以使用以下命令:head -c 3 file | od -t x1
    【解决方案4】:

    除了将 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
    

    【讨论】:

      【解决方案5】:

      我知道这个问题是针对 unix/linux 的,我认为对于 unix 挑战者来说,值得一提的是一个不错的选择(在 Windows 上,带有 UI)。
      我在一个 WordPress 项目中遇到了同样的问题(BOM 导致 rss 提要和页面验证出现问题),我不得不查看一个相当大的目录树中的所有文件,才能找到与 BOM 相关的文件。找到了一个名为 Replace Pioneer 的应用程序并在其中:

      Batch Runner -> 搜索(查找子文件夹中的所有文件)-> 替换模板 -> 二进制删除 BOM(为此有现成的搜索和替换模板)。

      这不是最优雅的解决方案,它确实需要安装程序,这是一个缺点。但是一旦我发现我周围发生了什么,它就像一个魅力(并在大约 2300 个带有 BOM 的文件中找到了 3 个)。

      【讨论】:

      • 当我找到您的解决方案时我很高兴,但是我没有权限在公司计算机上安装软件。今天花了很多时间,直到我找到替代方案:Using Notepad++ with PythonScript plugin 。 superuser.com/questions/418515/… 无论如何谢谢!
      猜你喜欢
      • 2013-08-10
      • 1970-01-01
      • 1970-01-01
      • 2011-04-21
      • 2015-01-01
      • 2010-09-22
      • 2011-10-30
      • 1970-01-01
      • 2023-03-10
      相关资源
      最近更新 更多