はじめに
普段はC++の記事を投稿しています。
Windows使いなもんで、Bashを使うのに
- Cmder + ComEmu + MSYS2 + bash
- Cmder + ComEmu + MSYS2 + bash + SSHでLinuxへ + bash
- Cmder + ComEmu + MSYS2 + bash + SSHでLinuxへ + bash + prootでarchilinuxを動かして + 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
コマンドを使うのが王道なんでしょう。
問題点
nkf
コマンドもuconv
コマンドも普通(CentOS 7)入っていないんですね!
ではどうするか
解決の糸口となったのがこの記事です。
Bash/Zsh スクリプトならバイナリを扱える。さて何をしよう……
http://qiita.com/akinomyoga/items/215faa630508ffc6e6e0
どうやらbash/zshでならバイナリを扱えるというではないですか。
つまり
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
にしても動くんですが、うーむ、わかんねぇ。