LoginSignup
35
25

More than 1 year has passed since last update.

UTF-8 BOMを確認・追加・削除するコマンド

Posted at

MacOSX環境にて、コマンドでBOMの確認や追加・削除の必要がありましたので、方法を整理します。
bashとhead, sedコマンドを利用した方法なので、LinuxやAlpine Linuxなどのコンテナ環境、その他Unix、WindowsのGit Bash, MinGW環境でも動かしやすいはず。

背景

Microsoft Excelでは UTF-8エンコードのCSVファイルを読み込んだり、書き出したりできますが、BOMが付きます。
データ移行のため、顧客から受領したExcelファイルを元に、CSV出力したものをベースに、移行用のデータ加工を行う必要がありました。

fileコマンドを使う簡単な確認方法があります。
しかし、csvファイルを判定しようとしたとき、手元のMacOSX環境のfileコマンドでは は判定結果がBOM有無に関わらずCSV textと出力され、その後のエンコード情報は出力してくれませんでした。
fileコマンドは、BSD系、System-V系の差異に加え、環境のmagicデータベースにも依存しますので、どの環境でも同じ出力が得られないのが難点です。

# よくある BOMなし、BOM付き UTF-8 テキストファイル
% file foo-no-bom.txt foo-with-bom.txt
foo-no-bom.txt:   UTF-8 Unicode text
foo-with-bom.txt: UTF-8 Unicode (with BOM) text

# しかし、CSVファイルではBOM有無を判別できない
% file data-no-bom.csv data-with-bom.csv
data-no-bom.csv:   CSV text
data-with-bom.csv: CSV text

 確認方法

UTF-8 BOM 確認その1 (fileコマンド encoding指定)

fileコマンドの-eオプションを使い、判定をencodingのみにします。
MacOSX環境でも、これでCSVファイルの判定ができます。

# -e encodingオプション指定でfileのエンコードを確認
% file -e encoding data-no-bom.csv data-with-bom.csv
data-no-bom.csv:   UTF-8 Unicode text, with CRLF line terminators
data-with-bom.csv: UTF-8 Unicode (with BOM) text, with CRLF line terminators

UTF-8 BOM 確認その2 (先頭byteを見る)

BOMはファイル先頭に付く数バイトの識別用バイナリなので、直接ファイル先頭を調べて判定ができるはずです。
UTF-8 BOM の場合は 0xEF 0xBB 0xBF ですね。
参考: バイト順マーク - Wikipedia

以下は headコマンドで先頭3byteを切り出して判定しています。
※比較にシェルの拡張書式$''を使っているので、対応したシェル環境(bash, zsh, ashなど)で使ってください。

もちろん、perlでもrubyでもpythonでも何でもお好きなスクリプト言語を用いても良いでしょう。

# ファイルfile.txtがUTF-8 BOMを持つか確認する
[[ $(head -c 3 file.txt) == $'\xef\xbb\xbf' ]] && echo 'has utf8 bom!!'

UTF-8 BOM 追加

# BOMなしファイルfile.txtにUTF-8 BOMを追加する
LC_ALL=C sed -e $'1s/^/\xef\xbb\xbf/' file.txt > file-with-bom.txt

UTF-8 BOM 削除

# BOM付きファイルfile.txtからUTF-8 BOMを削除する
LC_ALL=C sed -e $'1s/^\xef\xbb\xbf//' file.txt > file-no-bom.txt

コマンド化

よく使うなら、シェルスクリプト or シェル関数にしてコマンドとして使えるようにしておくと良いでしょう。

has-utf8-bom
#!/bin/bash
# UTF-8 BOM 確認
[[ $(LC_ALL=C head -c 3 -- "$@") == $'\xef\xbb\xbf' ]]
add-utf8-bom
#!/bin/bash
# UTF-8 BOM 追加
LC_ALL=C sed -e $'1s/^/\xef\xbb\xbf/' -- "$@"
remove-utf8-bom
#!/bin/bash
# UTF-8 BOM 削除
LC_ALL=C sed -e $'1s/^\xef\xbb\xbf//' -- "$@"

使い方例

例として、あるディレクトリ以下の UTF-8 BOM付きファイルを探して
元ファイルは .bak をつけてリネームし、BOMを削除したファイルを作成する、
というケース↓

# ディレクトリ ./src 以下のファイルを探して、UTF-8 BOMがついていれば削除する
find ./src -type f | while read F; do has-utf8-bom "$F" && mv "$F" "$F.bak" && remove-utf8-bom "$F.bak" > "$F" ; done

Gistにも掲載しておきましたので、ご参考に。

ライセンス

本記事に記載したコードは CC0 (Public Domain)です。

参考

35
25
1

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
35
25