MAC OSXでsedした時の sed: RE error: illegal byte sequence エラー
なぜかよくわからんが、OSXでsedを使っているとたまにタイトルのエラーに遭遇することがちょこちょこあります。
対処方法はロケールをC(POSIX)に指定することらしいけれど、そもそもなぜこれが発生するのかよくわからなかったので調べてみました。
発生した環境
今回このエラーが発生したのは、特定のディレクトリ以下にあるファイル内の文字列を一括置換しようとしたタイミングでした。 コマンドで言うとこんな感じ。
$ find . -type f | xargs sed -i .bak s/hoge/fuga/
エラーとしてはタイトルの通りsed: RE error: illegal byte sequence
となっていました。
改めて対象ファイルを見てみる
実際のものは見せられないので、それっぽい再現ですがこんな感じでした。
$ ls -la total 32 drwxr-xr-x 5 t-sei 2125026295 170 1 13 23:21 . drwx------+ 24 t-sei 2125026295 816 1 13 23:17 .. -rw-r--r-- 1 t-sei 2125026295 6149 1 13 23:19 .DS_Store -rw-r--r-- 1 t-sei 2125026295 5 1 13 23:20 fuga.txt -rw-r--r-- 1 t-sei 2125026295 5 1 13 23:20 hoge.txt
上から三番目に何か怪しい奴が居ますね。彼をsed
に投げてみます
$ sed s/hoge/fuga/ .DS_Store sed: RE error: illegal byte sequence
ビンゴ!さっそく犯人を見つけました。やはりOSXユーザは.DS_Store
とうまく付き合う方法を学ばねばならないようです。
なぜsed
に.DS_Store
を渡すとエラーになるのか?
エラー文言を見る限り、不正なバイト列が渡ってきてるんだよねという話のようです。 しかし一方で、ロケールの設定を変更することでこのエラーは発生しなくなりますので、なぜなのか調べてみました。
とりあえずググってみると、UNIX WARE7のsedページでそれっぽい記述を見つけました。
sed は 環境変数 LC_CTYPE (environ(5) の LANG を参照) に指定されたロケールに従って、script ファイル中の注釈の補助コードセットを処理します。 ただし、後述する y コマンドに関しては例外です。ed(1) で説明しているように、正規表現ではパターン検索をバイト単位ではなく文字単位で行います。
なるほど、LC_ALL
(LC_CTYPE
)の設定を変えることで挙動が変わる理由がわかりました。
つまり、OSXのデフォルトロケール設定のsed
では.DS_Store
のようなバイナリファイルを解釈出来ないということのようです。
ちなみにLC_CTYPE
環境変数はOpenGroupのオンラインヘルプによると、
文字などのテキストデータのバイトシーケンスの解釈や文字の分類をする際に参照されるようです。
(追記)挙動と環境変数に関してはOpenGroupの sedページ見るのが一番よさそうだった。
私の環境では下記のようになっていました。
$ locale LANG="ja_JP.UTF-8" LC_COLLATE="ja_JP.UTF-8" LC_CTYPE="ja_JP.UTF-8" LC_MESSAGES="ja_JP.UTF-8" LC_MONETARY="ja_JP.UTF-8" LC_NUMERIC="ja_JP.UTF-8" LC_TIME="ja_JP.UTF-8" LC_ALL=
ja_JP.UTF-8
を期待しているところにバイナリファイルである.DS_Store
を叩きこまれて解釈出来ずに困ってしまったということでした。
今後、同様のエラーが出た時に参考にしていただければ幸いです。