ShellScript
Bash
UTF-8
bom

bashでもUTF-8 with BOMなファイルを作りたい


はじめに

普段はC++の記事を投稿しています。

Windows使いなもんで、Bashを使うのに

とかしてやってます(どんだけ間に挟むんだ)


動機

ちょっとcsvを自動加工する必要が出てきまして、Windows向けにpowershellとLinux向けにShellScript(on bash)を書くことになったんですね。

要件として、出力ファイルはUTF-8 with BOMにしたいというものがありまして、powershellだと

"arikitari" | out-file -encoding:utf8 $out_file

"na" | Add-Content -encoding:utf8 $out_file
"world!" | Add-Content -encoding:utf8 $out_file

とかすれば良かったりするんですが、はて、これはShellScript(on bash)ではどうすればいいのかな、と。


先行例

コマンドラインでUTF-8テキストのBOMを追加したり削除したりする – skmks

もちろんそういうことを思う人は私だけではないわけで、先行例がありました。

ここではnkfコマンドとuconvコマンドを使う2つの例が出ていました。

そして多分、nkfコマンドを使うのが王道なんでしょう。


問題点

image

nkfコマンドもuconvコマンドも普通(CentOS 7)入っていないんですね!


ではどうするか

解決の糸口となったのがこの記事です。

Bash/Zsh スクリプトならバイナリを扱える。さて何をしよう……

http://qiita.com/akinomyoga/items/215faa630508ffc6e6e0

どうやらbash/zshでならバイナリを扱えるというではないですか。

つまり


UTF-8のBOM

0xEF 0xBB 0xBF


を直接書き込めばいいわけです。


というわけで実装した

#!/bin/bash

function writebinary {
LC_ALL=C printf "$(printf '\\x%x' "${data[@]}")" > "$1"
}
function write_utf8_bom {
#BOM:0xEF 0xBB 0xBF
local -a data=(239 187 191)
writebinary $1
}
write_utf8_bom bom.txt
echo "arikitari" >> bom.txt
echo "na" >> bom.txt
echo "world!" >> bom.txt

確認してみましょう。

$hexdump -C bom.txt

00000000 ef bb bf 61 72 69 6b 69 74 61 72 69 0a 6e 61 0a |...arikitari.na.|
00000010 77 6f 72 6c 64 21 0a |world!.|
00000017

いいですね。


追記

@kkdd さんから教えてもらったので。

まずechoコマンドのmanを覗いてみましょう。

ECHO(1)                                                                                                 User Commands                                                                                                ECHO(1)

NAME
echo - display a line of text

SYNOPSIS
echo [SHORT-OPTION]... [STRING]...
echo LONG-OPTION

DESCRIPTION
Echo the STRING(s) to standard output.

-n do not output the trailing newline

-e enable interpretation of backslash escapes

改行を阻止する-nとエスケープを使えるようにする-eを組み合わせると

#!/bin/bash

function f()
{
echo -en '\xef\xbb\xbf'
echo "arikiari"
echo "na"
echo "world!"
}
f > bom.txt

$hexdump -C bom.txt

00000000 ef bb bf 61 72 69 6b 69 61 72 69 0a 6e 61 0a 77 |...arikiari.na.w|
00000010 6f 72 6c 64 21 0a |orld!.|
00000016

同じ結果が得られたゾイ!これはいい。教えていただきありがとうございます。


余談

ところでこれ、#!/bin/bash#!/bin/shにしても動くんですが、うーむ、わかんねぇ。


License

CC BY 4.0

CC-BY icon.svg