【问题标题】:How can I re-add a unicode byte order marker in linux?如何在 linux 中重新添加 unicode 字节顺序标记?
【发布时间】:2010-11-05 21:17:22
【问题描述】:

我有一个相当大的 SQL 文件,它以 FFFE 的字节顺序标记开头。我已经使用 unicode 感知 linux 拆分工具将此文件拆分为 100,000 行块。但是当将这些传回窗口时,它喜欢除第一个以外的任何部分,因为它只有 FFFE 字节顺序标记。

如何使用 echo(或任何其他 bash 命令)添加这两个字节代码?

【问题讨论】:

    标签: linux bash unicode


    【解决方案1】:

    类似(先备份)):

    for i in $(ls *.sql)
    do
      cp "$i" "$i.temp"
      printf '\xFF\xFE' > "$i"
      cat "$i.temp" >> "$i"
      rm "$i.temp"
    done
    

    【讨论】:

    • 打印!谢谢伙计,我想我一直在谷歌搜索直到时间结束!
    • BOM 代码点为 U+FEFF,但其在 UTF-8 中的文字表示为 EF BB BF(三个字节)。这只有在文件已经是 UTF-16、小端序时才有效。见en.wikipedia.org/wiki/…
    【解决方案2】:

    Matthew Flaschen 的回答不错,但也有一些缺陷。

    • 在原始文件被截断之前没有检查复制是否成功。最好让一切都以成功的复制为条件,或者测试临时文件的存在,或者对副本进行操作.如果你是一个系腰带和吊带的人,你会像我在下面展示的那样做一个组合
    • ls 是不必要的。
    • 我会使用比“i”更好的变量名——也许是“file”。

    当然,您可能非常偏执并在开始时检查临时文件的存在,以免意外覆盖它和/或使用 UUID 或生成的文件名。 mktemp、tempfile 或 uuidgen 之一可以解决问题。

    td=TMPDIR
    export TMPDIR=
    
    usertemp=~/temp            # set this to use a temp directory on the same filesystem
                               # you could use ./temp to ensure that it's one the same one
                               # you can use mktemp -d to create the dir instead of mkdir
    
    if [[ ! -d $usertemp ]]    # if this user temp directory doesn't exist
    then                       # then create it, unless you can't 
        mkdir $usertemp || export TMPDIR=$td    # if you can't create it and TMPDIR is/was
    fi                                          # empty then mktemp automatically falls
                                                # back to /tmp
    
    for file in *.sql
    do
        # TMPDIR if set overrides the argument to -p
        temp=$(mktemp -p $usertemp) || { echo "$0: Unable to create temp file."; exit 1; }
    
        { printf '\xFF\xFE' > "$temp" &&
        cat "$file" >> "$temp"; } || { echo "$0: Write failed on $file"; exit 1; }
    
        { rm "$file" && 
        mv "$temp" "$file"; } || { echo "$0: Replacement failed for $file; exit 1; }
    done
    export TMPDIR=$td
    

    陷阱可能比我添加的所有单独的错误处理程序更好。

    毫无疑问,所有这些额外的谨慎对于一次性脚本来说都是多余的,但这些技术可以在紧急情况下为您节省开支,尤其是在多文件操作中。

    【讨论】:

    • 不需要“cp”命令。 "mktemp" 还会在 /tmp 中返回一个名称;最好将临时文件写在同一个文件系统上,这样“mv”就不必复制它了。
    • @mark4o:你在这两个方面都是正确的。我已经相应地更新了我的答案。
    【解决方案3】:

    对于通用解决方案——无论文件是 UTF-8、UTF-16 还是 UTF-32 都设置正确的字节顺序标记——我会使用 vim 的 'bomb' 选项:

    $ echo 'hello' > foo
    $ xxd < foo
    0000000: 6865 6c6c 6f0a                           hello.
    $ vim -e -s -c ':set bomb' -c ':wq' foo
    $ xxd < foo
    0000000: efbb bf68 656c 6c6f 0a                   ...hello.
    

    -e 表示以 ex 模式而不是可视模式运行;-s 表示不打印状态消息;-c 表示“执行此操作”)

    【讨论】:

      【解决方案4】:

      要向所有以“foo-”开头的文件添加 BOM,您可以使用sedsed 可以选择进行备份。

      sed -i '1s/^\(\xff\xfe\)\?/\xff\xfe/' foo-*
      

      straceing 这表明 sed 创建了一个名称以“sed”开头的临时文件。如果您确定已经没有 BOM,则可以简化命令:

      sed -i '1s/^/\xff\xfe/' foo-*
      

      确保您需要设置 UTF-16,因为即 UTF-8 不同。

      【讨论】:

      • 对于 UTF-8 使用 \xef\xbb\xbf;对于 UTF-16 little-endian 使用 \xff\xfe;对于 UTF-16 大端使用 \xfe\xff。见w3.org/International/questions/qa-byte-order-mark
      • 赞成这个答案,因为这是我自己使用的。 Mac OS 和其他 BSD 用户应该注意-i,--inplace 选项不是由 POSIX 指定的,并且仅适用于 GNU sed。
      • 顺便说一句,g(全局)修饰符在这里没有任何作用。
      【解决方案5】:

      试试 uconv

      uconv --add-signature
      

      【讨论】:

      • uconv 需要安装(在 Debian 中,它位于 libicu-dev 包中)。如果文件采用不同的编码,并不是说添加签名不起作用。
      【解决方案6】:

      基于 sed 的 solution of Anonymoussed -i '1s/^/\xef\xbb\xbf/' foo 将 BOM 添加到 UTF-8 编码文件 foo。有用的是它还可以将 ASCII 文件转换为带有 BOM 的 UTF8

      【讨论】:

        【解决方案7】:
        $ printf '\xEF\xBB\xBF' > bom.txt
        

        然后检查:

        $ grep -rl $'\xEF\xBB\xBF' .
        ./bom.txt
        

        【讨论】:

          猜你喜欢
          • 2010-09-17
          • 2016-05-10
          • 2014-07-08
          • 2015-07-07
          • 2014-12-24
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2018-10-18
          相关资源
          最近更新 更多