初歩のシェルスクリプトで遊ぶ[シフトJISをutf8に変換-4,メガネハナーンの切れ端からガリバー旅行記を組み立てる]

調べものには使えません。
Ubuntu18.04,Virtualbox6.1.2,dash,bash

シフトJISテキストファイル→utf8の16進数→utf8テキストファイル

スクリプトは後に置いとくとして、作ったスクリプトを通して動かします。
あらためて方針を説明。

  • Windowsのテキストファイル(cp932)を、Linux環境で読めるようにしたい。
  • 出発はodコマンドのダンプ。
  • ただし、妥協はする。
  • 不具合があっても、読めればよし。
  • 最低限の簡易型でいい。
  • 趣味で個人が読むテキストファイルを変換するのに、十分な変換速度は目指す。
  • 処理の無駄を省くよりも、回り道することを優先する。
妥協点
  • 辞書ファイルを作るときに、iconvコマンドを使った
  • 辞書ファイルを作るときに、xxdコマンドを使った

xxdコマンドを使わなくても、任意のバイナリデータを作れる、ということは示したので、下のスクリプトではxxdコマンドにしてます。
メガネハナーンバイナリ作成機の使用例も兼ねて、参考にcp932の文字リスト(7882文字)を、ダンプリストからテキストファイルに変換した結果。

$ cat cp932dump.txt | head
20 21 22 23 24 25 26 27 28 29 2A 2B 2C 2D 2E 2F 30 31 32 33 34 35 36 37 38 39
3A 3B 3C 3D 3E 3F 40 41 42 43 44 45 46 47 48 49 4A 4B 4C 4D 4E 4F 50 51 52 53
54 55 56 57 58 59 5A 5B 5C 5D 5E 5F 60 61 62 63 64 65 66 67 68 69 6A 6B 6C 6D
6E 6F 70 71 72 73 74 75 76 77 78 79 7A 7B 7C 7D 7E A1 A2 A3 A4 A5 A6 A7 A8 A9
AA AB AC AD AE AF B0 B1 B2 B3 B4 B5 B6 B7 B8 B9 BA BB BC BD BE BF C0 C1 C2 C3
C4 C5 C6 C7 C8 C9 CA CB CC CD CE CF D0 D1 D2 D3 D4 D5 D6 D7 D8 D9 DA DB DC DD
DE DF
8140 8141 8142 8143 8144 8145 8146 8147 8148 8149 814A 814B 814C 814D 814E 814F
8150 8151 8152 8153 8154 8155 8156 8157 8158 8159 815A 815B 815C 815D 815E 815F
8160 8161 8162 8163 8164 8165 8166 8167 8168 8169 816A 816B 816C 816D 816E 816F
$ time 0< cp932dump.txt dash ./binCreator_02.sh >cp932txt_hananegane.txt
real	0m0.349s
user	0m0.083s
sys	0m0.220s
$ time 0< cp932dump.txt xxd -r -p >cp932txt_xxd.txt
real	0m0.004s
user	0m0.002s
sys	0m0.001s
$ md5sum cp932txt_*
50ca0b7bc00087c8ea64581da94625a8  cp932txt_hananegane.txt
50ca0b7bc00087c8ea64581da94625a8  cp932txt_xxd.txt
$ cat cp932txt_hananegane.txt | iconv -f cp932 | cut -c 1-2100
 !"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~。「」、・ヲァィゥェォャュョッーアイウエオカキクケコサシスセソタチツテトナニヌネノハヒフヘホマミムメモヤユヨラリルレロワン゙゚ 、。,.・:;?!゛゜´`¨^ ̄_ヽヾゝゞ〃仝々〆〇ー―‐/\~∥|…‥‘’“”()〔〕[]{}〈〉《》「」『』【】+-±×÷=≠<>≦≧∞∴♂♀°′″℃¥$¢£%#&*@§☆★○●◎◇◆□■△▲▽▼※〒→←↑↓〓∈∋⊆⊇⊂⊃∪∩∧∨¬⇒⇔∀∃∠⊥⌒∂∇≡≒≪≫√∽∝∵∫∬ʼn♯♭♪†‡¶◯0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyzぁあぃいぅうぇえぉおかがきぎくぐけげこごさざしじすずせぜそぞただちぢっつづてでとどなにぬねのはばぱひびぴふぶぷへべぺほぼぽまみむめもゃやゅゆょよらりるれろゎわゐゑをんァアィイゥウェエォオカガキギクグケゲコゴサザシジスズセゼソゾタダチヂッツヅテデトドナニヌネノハバパヒビピフブプヘベペホボポマミムメモャヤュユョヨラリルレロヮワヰヱヲンヴヵヶΑΒΓΔΕΖΗΘΙΚΛΜΝΞΟΠΡΣΤΥΦΧΨΩαβγδεζηθικλμνξοπρστυφχψωАБВГДЕЁЖЗИЙКЛМНОПРСТУФХЦЧШЩЪЫЬЭЮЯабвгдеёжзийклмнопрстуфхцчшщъыьэюя─│┌┐┘└├┬┤┴┼━┃┏┓┛┗┣┳┫┻╋┠┯┨┷┿┝┰┥┸╂①②③④⑤⑥⑦⑧⑨⑩⑪⑫⑬⑭⑮⑯⑰⑱⑲⑳ⅠⅡⅢⅣⅤⅥⅦⅧⅨⅩ㍉㌔㌢㍍㌘㌧㌃㌶㍑㍗㌍㌦㌣㌫㍊㌻㎜㎝㎞㎎㎏㏄㎡㍻〝〟№㏍℡㊤㊥㊦㊧㊨㈱㈲㈹㍾㍽㍼≒≡∫∮∑√⊥∠∟⊿∵∩∪亜唖娃阿哀愛挨姶逢葵茜穐悪握渥旭葦芦鯵梓圧斡扱宛姐虻飴絢綾鮎或粟袷安庵按暗案闇

できてますね。

ガリバー旅行記』を通して変換してみる

図書カード:ガリバー旅行記

$ 0< gulliver_ryokoki.txt ./sjisTextToUtf8Code02.sh | head
 e3 82 ac e3 83 aa e3 83 90 e3 83 bc e6 97 85 e8 a1 8c e8 a8 98 0a 47 55 4c 4c 49 56 45 52 27
 53 20 54 52 41 56 45 4c 53 0a e3 82 b8 e3 83 a7 e3 83 8a e3 82 b5 e3 83 b3 e3 83 bb e3 82 b9
 e3 82 a4 e3 83 95 e3 83 88 e3 80 80 4a 6f 6e 61 74 68 61 6e 20 53 77 69 66 74 0a e5 8e 9f e6
 b0 91 e5 96 9c e8 a8 b3 0a 0a 2d 2d 2d 2d 2d 2d 2d 2d 2d 2d 2d 2d 2d 2d 2d 2d 2d 2d 2d 2d 2d
 2d 2d 2d 2d 2d 2d 2d 2d 2d 2d 2d 2d 2d 2d 2d 2d 2d 2d 2d 2d 2d 2d 2d 2d 2d 2d 2d 2d 2d 2d 2d
 2d 2d 2d 0a e3 80 90 e3 83 86 e3 82 ad e3 82 b9 e3 83 88 e4 b8 ad e3 81 ab e7 8f be e3 82 8c
 e3 82 8b e8 a8 98 e5 8f b7 e3 81 ab e3 81 a4 e3 81 84 e3 81 a6 e3 80 91 0a 0a e3 80 8a e3 80
 8b ef bc 9a e3 83 ab e3 83 93 0a ef bc 88 e4 be 8b ef bc 89 e3 83 9c e3 83 bc e3 83 88 e3 82
 92 e6 bc 95 e3 80 8a e3 81 93 e3 80 8b e3 81 90 0a 0a ef bd 9c ef bc 9a e3 83 ab e3 83 93 e3
 81 ae e4 bb 98 e3 81 8f e6 96 87 e5 ad 97 e5 88 97 e3 81 ae e5 a7 8b e3 81 be e3 82 8a e3 82

青空文庫のテキストファイルを読ませると、16進数をダーッと出力します。
まず単体で測定。次に、パイプで繋いで実行します。

$ time 0< gulliver_ryokoki.txt ./sjisTextToUtf8Code02.sh 1>/dev/null
real	0m6.121s
user	0m4.461s
sys	0m2.333s
$ time 0< gulliver_ryokoki.txt ./sjisTextToUtf8Code02.sh 1>gulliver_dump.txt
real	0m6.272s
user	0m4.951s
sys	0m1.995s
$ time 0< gulliver_dump.txt ./binCreator_02.sh 1>/dev/null
real	0m5.029s
user	0m2.082s
sys	0m2.822s
$ time 0< gulliver_ryokoki.txt ./sjisTextToUtf8Code02.sh | ./binCreator_02.sh 1>/dev/null
real	0m11.066s
user	0m6.830s
sys	0m4.655s
$ 0< gulliver_ryokoki.txt ./sjisTextToUtf8Code02.sh | ./binCreator_02.sh 1>gulliver_ryokoki_hanamegane.txt
$ 0< gulliver_ryokoki.txt iconv -f SHIFT-JIS | dos2unix 1> gulliver_ryokoki_iconv.txt 
$ md5sum gulliver_ryokoki*
027a5821339608be2732d99d230ecfd0  gulliver_ryokoki.txt
33dcc1a4af39fa292ff422e875abf2e6  gulliver_ryokoki_hanamegane.txt
33dcc1a4af39fa292ff422e875abf2e6  gulliver_ryokoki_iconv.txt
33dcc1a4af39fa292ff422e875abf2e6  gulliver_ryokoki_pluma.txt
33dcc1a4af39fa292ff422e875abf2e6  gulliver_ryokoki_sakura.txt

「pluma」「サクラエディタ」で変換したファイルも添えました。okっすね。

おわり。きりがない。

スクリプトファイル

他人が見ることが物理的に可能なブログに置く以上、最低限の気は遣ってますけど、正直あんまり……こんなもん、誰が実行するんだと。
トラブルがあっても責任は取れません。

スクリプトの内訳

2つは、以前のエントリに載せてます。
WindowsのシフトJISの文字リストを作るシェルスクリプト - HatenaDiary id:Narr

  • 文字コードから辞書を作るスクリプトx4個 [ cp932dicMaker1.sh , sjisTextToUtf8Code01_dic11.sh , sjisTextToUtf8Code01_dic12.sh , sjisTextToUtf8Code01_dic11.sh]
  • cp932テキストファイルをutf8のダンプリストに変換するスクリプト[sjisTextToUtf8Code02.sh]

これら5つは、下に置きました。

  • ダンプリストからバイナリ(今回はテキストファイル)を作るスクリプト

ひとつ前のエントリに。メガネハナーンの奴でなくてもいいです。
もちろんxxdのほうがいい。

注意とか

xxdコマンドが必要です。辞書を作るのに。
iconvも必要ですが、既に入ってる確率高いと思う。
あとは、辞書ファイルのパスを書くくらいです。

辞書ファイルを作るときは、「sjisTextToUtf8Code01_dic13.sh」がまとめ役ですんで、これのコメント見てください。ぜんぶまとめて自動実行できます。
ここに置いた辞書ファイル作成スクリプトは、検査用の中間ファイルを作る形式です。フォルダを新規作成して、そのフォルダの中にたくさん作ります。

cp932dicMaker1.sh

#!/bin/sh
#set -x
: << '#--------------------------------------------------------------comment'
■ 辞書作成中間ファイル作成スクリプト

▼ 必要なコマンド

XXD(1)                       General Commands Manual  XXD(1)---引用
名前
       xxd - 16 進ダンプを作成したり、元に戻したり。

ICONV(1)                        Linux User Manual   ICONV(1)---引用
NAME
       iconv - convert text from one character encoding to another

▼つかいかた
1)作業ディレクトリを作って、下記3個のスクリプトファイルを置く。
cp932CharMaker3.sh 
cp932CharMaker4.sh 
cp932dicMaker1.sh (このスクリプト)

2)実行
cp932dicMaker1.sh (このスクリプト)を実行する。

▼生成物 cp932hex-utf8hex.txt

 100 7c , 7c 
 100 7d , 7d 
 100 7e , 7e 
 100 a1 , ef bd a1 
 100 a2 , ef bd a2 
 100 a3 , ef bd a3 

cp932の16進数,utf8の16進数
(1バイト文字は0x100を追加)
7885行
149,021 bytes

#--------------------------------------------------------------comment


echo "cp932の1バイト文字部分を作る(158行)" 1>&2
./cp932CharMaker3.sh | tr A-F a-f | tr " " "\n" | sed "s/../100 &/;s/.*/ & /" 1> 1byteFile.temp

echo "cp932の2バイト文字部分を作る(7724行)" 1>&2
./cp932CharMaker4.sh | tr A-F a-f | fold -w 5 | tr -d " " | sed "s/../& /;s/.*/ & /" 1> 2byteFile.temp

echo "1バイト文字と2バイト文字のテキストファイルを繋ぐ(7882行)" 1>&2
cat 1byteFile.temp 2byteFile.temp 1> cp932Code.txt
echo "掃除" 1>&2
rm 1byteFile.temp 2byteFile.temp


echo "あらためて最初から材料を用意する。今度は一つのファイルに追記する。" 1>&2
./cp932CharMaker3.sh 1> cp932.temp
./cp932CharMaker4.sh 1>>cp932.temp

echo "シフトJISの読めるテキストファイルに変換する" 1>&2
0< cp932.temp xxd -r -p 1> cp932text.temp
echo "掃除" 1>&2
rm cp932.temp

echo "シフトJIS(cp932)をutf8に変換する" 1>&2
0< cp932text.temp iconv -f cp932 -t utf8 1> utf8text.temp
echo "掃除" 1>&2
rm cp932text.temp

echo "1行1文字に改行を入れて(grep) | バイナリデータを読み取り(od) | 見た目の改行を削除して(tr) |" 1>&2
echo "改行データ「0a」を「@」に入れ替え(sed) | 「@」で改行して(tr) 1> ファイルに書き込む " 1>&2
0< utf8text.temp  grep -o .| od -An -tx1 | tr -d "\n" | sed "s/0a/@/g" | tr "@" "\n" 1> utf8Code.txt
echo "掃除" 1>&2
rm utf8text.temp

echo "不足分の改行「0d0a」「0a」水平タブ「09」を最初に入れてから" 1>&2
echo " 0d 0a , 0a "  1>  cp932hex-utf8hex.txt
echo " 100 0a , 0a " 1>> cp932hex-utf8hex.txt
echo " 100 09 , 09 " 1>> cp932hex-utf8hex.txt
echo "cp932とutf8をカンマ区切りで横に繋げた(paste)ものを、追記する" 1>&2
paste -d , cp932Code.txt utf8Code.txt 1>> cp932hex-utf8hex.txt
echo "掃除" 1>&2
rm cp932Code.txt utf8Code.txt 

echo "こんなん作った" 1>&2
0< cp932hex-utf8hex.txt head 1>&2


exit 0

sjisTextToUtf8Code01_dic11.sh

#!/bin/dash
#set -x
: << '#--------------------------------------------------------------comment'
■10進数アドレス辞書作成スクリプト 〜utf8 16進数コード版

▼用意するデータファイル
別途スクリプトで作成する。
1バイトごとに空白が入っていること。カンマも空白で挟むこと。
1バイト文字の上位バイトは、0xの「100」とする。但し、これは「1 00」ではダメ

sjis , utf8
100 de , ef  be  9e 
100 df , ef  be  9f 
81 40 , e3  80  80 
81 41 , e3  80  81 

▼作成されるファイル形式
 e8 96 a6, e8 a9 ae, e8 b3 8e, e8 b7 b5, e9 81 b8, e9 81 b7,

行は10進数で文字コードの上位バイト
列も同様に、文字コードの下位バイト

▼使用方法
「辞書作成中間ファイル作成スクリプトcp932dicMaker1.sh」で、
作成元の辞書ファイルを用意し、パスに指定して、実行

▼速度
$ time dash ./sjisTextToUtf8Code01_dic11.sh 
real	0m5.749s
user	0m3.615s
sys	0m1.873s

#--------------------------------------------------------------comment

# 辞書の元になるテキストファイルのパス
dic="./cp932hex-utf8hex.txt"
if ls "${dic}" ;then true ;else exit 1 ; fi

# 作業ディレクトリ作成
mkdir codeLineDir 2>/dev/null

sjisTextToUtf8Code01_dic11_1(){
: << '#--------------------------------------------------------------comment'
・cp932上位バイトについて、同じバイトの行をそれぞれ1つのファイルにまとめる
・cp932コードを、1バイトごとに10進数に変換する
・1バイト文字の上位バイトは「100」として入力すること
#--------------------------------------------------------------comment

while read sjisCodeHexU sjisCodeHexL x transCodeHex ;do

sjisCodeDecU=$((0x${sjisCodeHexU}))
sjisCodeDecL=$((0x${sjisCodeHexL}))

sjisCodeDec00U=`printf '%03d' ${sjisCodeDecU}`
sjisCodeDec00L=`printf '%03d' ${sjisCodeDecL}`

# /bin/dash 「078,L%4e%R」「199,=%ef be 87 %=」
# /bin/bash 「078,L%4e%R」「199,=%ef be 87%=」
# ↑空白の不揃いに注意(readの変数分割が原因)

#     ソート用10進        L% utf8 %R
echo "${sjisCodeDec00L},=%${transCodeHex}%=" 1>> ./codeLineDir/${sjisCodeDec00U}_dic11_1.temp

done 0< "${dic}"
echo 'sjisTextToUtf8Code01_dic11_1 終了' 1>&2
return 0
}


sjisTextToUtf8Code01_dic11_2(){
: << '#--------------------------------------------------------------comment'
・???_dic11_1.tempファイル群のデータを整え、中間ファイルに書き出す。
・並び替え[sort],重複削除[uniq]
・不安定な空白を一旦全て削除[tr -d " "]
・cp932コードの下位1バイト(10進数)が、生成ファイルの行番号と一致するか確認する
#--------------------------------------------------------------comment
for lineFile in `echo ./codeLineDir/*_dic11_1.temp` ;do

lineFileTemp=`sort ${lineFile} | uniq | tr -d " "`
sjisCodeDecU=`echo ${lineFile} | sed 's@..codeLineDir.\([0-9]\{3\}\)_dic11_1.temp@\1@'`

												decLcount=0
while IFS=, read sjisCodeDecL00 utf8CodeHex;do
												decLcount=$((decLcount+1))

	# データの無い列を埋める
	while test ${sjisCodeDecL00} -gt ${decLcount} ;do
	echo  "none_," 1>> ./codeLineDir/${sjisCodeDecU}_dic11_2.temp # 「none_」はdebug用の付加情報
												decLcount=$((decLcount+1))
	done

# 「${sjisCodeDecL00}_」はdebug用の付加情報で、後処理で削除する
echo  "${sjisCodeDecL00}_${utf8CodeHex}," 1>> ./codeLineDir/${sjisCodeDecU}_dic11_2.temp


done << ---LINE_FILE_TEMP
${lineFileTemp}
---LINE_FILE_TEMP
done
echo 'sjisTextToUtf8Code01_dic11_2 終了' 1>&2
return 0
}


sjisTextToUtf8Code01_dic11_3(){
: << '#--------------------------------------------------------------comment'
・???_dic11_2.tempファイル群を、1ファイルにまとめる
(行番号)=(cp932の上1バイトの10進数) にする。不足分の行を追加作成する。
#--------------------------------------------------------------comment
													decFileCount=0
for lineFile in `echo ./codeLineDir/*_dic11_2.temp` ;do
													decFileCount=$((decFileCount+1))

sjisCodeDecU=`echo ${lineFile} | sed 's@..codeLineDir.\([0-9]\{3\}\)_dic11_2.temp@\1@'`

# 中間ファイル「_2」からdebug情報を削除[cut]
# utf8 バイト列の空白調整[sed]
utf8CodeHex="`0< ${lineFile} cut -d _ -f 2 |
 sed -e 's@=%\(..\)\(..\)\(..\)%=@ \1 \2 \3@; s@=%\(..\)\(..\)%=@ \1 \2@; s@=%\(..\)%=@ \1@;'`"

	while test ${sjisCodeDecU} -gt ${decFileCount} ;do
	echo "" 1>> ./codeLineDir/composite_dic11_3
													decFileCount=$((decFileCount+1))
	done 

echo "${utf8CodeHex}" | tr -d "\n" 1>> ./codeLineDir/composite_dic11_3
echo "" 1>> ./codeLineDir/composite_dic11_3

done
echo 'sjisTextToUtf8Code01_dic11_3 終了' 1>&2
return 0
}

: << '#--------------------------------------------------------------comment'
 11_1 は単独で実行し、中間ファイルを作成する。
 11_2 は単独で実行し、11_1が作った中間ファイルから、さらに中間ファイルを作成する。
 11_3 は単独で実行し、11_2が作った中間ファイルから、完成ファイルを作成する。
 連続で実行しても構わない。
 テストで作成した古いファイルが残っている場合は、すべて削除してから実行する。
 中間ファイルは使用後に削除しても構わない。
#--------------------------------------------------------------comment

sjisTextToUtf8Code01_dic11_1 
sjisTextToUtf8Code01_dic11_2
sjisTextToUtf8Code01_dic11_3


exit 0

sjisTextToUtf8Code01_dic12.sh

#!/bin/dash
#set -x
: << '#--------------------------------------------------------------comment'
■10進数アドレス辞書作成スクリプト 〜utf8 16進数コード変数代入式版

▼用意するデータファイル
別途スクリプトで作成する。
1バイトごとに空白が入っていること。カンマも空白で挟むこと。
1バイト文字の上位バイトは、0xの「100」とする。但し、これは「1 00」ではダメ

sjis , utf8
100 de , ef  be  9e 
100 df , ef  be  9f 
81 40 , e3  80  80 
81 41 , e3  80  81 

▼作成されるファイル形式
 u256_125=" 7d"; u256_126=" 7e"; u256_161=" ef bd a1";
行は10進数で文字コードの上位バイト。「u256_」なら256行のみにある。
列に意味は無し。1行ずつ読み込んでまとめて実行する。

▼使用方法
「辞書作成中間ファイル作成スクリプトcp932dicMaker1.sh」で、
作成元の辞書ファイルを用意し、パスに指定して、実行


$ time dash ./sjisTextToUtf8Code01_dic12.sh
real	0m5.753s
user	0m3.446s
sys	0m2.031s

#--------------------------------------------------------------comment

# 辞書の元になるテキストファイルのパス
dic="./cp932hex-utf8hex.txt"
if ls "${dic}" ;then true ;else exit 1 ; fi

# 作業ディレクトリ作成
mkdir codeLineDir 2>/dev/null

sjisTextToUtf8Code01_dic12_1(){
: << '#--------------------------------------------------------------comment'
・cp932上位バイトについて、同じバイトの行をそれぞれ1つのファイルにまとめる
・cp932コードを、1バイトごとに10進数に変換する
・1バイト文字の上位バイトは「100」として入力すること
#--------------------------------------------------------------comment
while read sjisCodeHexU sjisCodeHexL x transCodeHex ;do

sjisCodeDecU=$((0x${sjisCodeHexU}))
sjisCodeDecL=$((0x${sjisCodeHexL}))

sjisCodeDec00U=`printf '%03d' ${sjisCodeDecU}`
sjisCodeDec00L=`printf '%03d' ${sjisCodeDecL}`

# readで変数を分割すると、utf8の空白が狂う。後で調整。
# 「%」は「"」に、最後に入れ替える。
# 【【【変数名はゼロ埋めしない】】】
# 変数名は区切りアンダースコア必須

#     ソート用10進        変数名U      _変数名L       =% utf8   %;
echo "${sjisCodeDec00L},u${sjisCodeDecU}_${sjisCodeDecL}=%${transCodeHex}%;" \
1>> ./codeLineDir/${sjisCodeDec00U}_dic12_1.temp

done 0< "${dic}" 
echo 'sjisTextToUtf8Code01_dic12_1 終了' 1>&2
return 0
}


sjisTextToUtf8Code01_dic12_2(){
: << '#--------------------------------------------------------------comment'
・cp932下位バイトについて、ソートを実行する。[sort]
・同一内容の行があれば、1行残して削除する。[uniq]
・不安定な空白を一旦全て削除[tr -d " "]
#--------------------------------------------------------------comment
for lineFile in `echo ./codeLineDir/*_dic12_1.temp` ;do
sjisCodeDecU=`echo ${lineFile} | sed 's@..codeLineDir.\([0-9]\{3\}\)_dic12_1.temp@\1@'`
lineFileTemp=`sort ${lineFile} | uniq | tr -d " "`

while IFS=, read sjisCodeDecL00 transCodeSubs;do
echo  "${transCodeSubs}" 1>> ./codeLineDir/${sjisCodeDecU}_dic12_2.temp

done << ---LINE_FILE_TEMP
${lineFileTemp}
---LINE_FILE_TEMP

done
echo 'sjisTextToUtf8Code01_dic12_2 終了' 1>&2
return 0
}


sjisTextToUtf8Code01_dic12_3(){
: << '#--------------------------------------------------------------comment'
???_dic12_2.tempファイル群を、1ファイルにまとめる
(行番号)=(cp932の上1バイトの10進数) にする。不足分の行を作成する。
#--------------------------------------------------------------comment
																decFileCount=0
for lineFile in `echo ./codeLineDir/*_dic12_2.temp` ;do

sjisCodeDecU=`echo ${lineFile} | sed 's@..codeLineDir.\([0-9]\{3\}\)_dic12_2.temp@\1@'`

																decFileCount=$((decFileCount+1))
while test ${sjisCodeDecU} -gt ${decFileCount} ;do
echo "" 1>> ./codeLineDir/composite_dic12_3
																decFileCount=$((decFileCount+1))
done 
# 空白の付与[sed],「%」→「"」置き換え[sed],改行の削除[tr],終了の改行[echo]
sed -e 's/%\(..\)%;/" \1"; /g;s/%\(..\)\(..\)%;/" \1 \2"; /g;s/%\(..\)\(..\)\(..\)%;/" \1 \2 \3"; /g;' "${lineFile}" |
tr -d "\n" 1>> ./codeLineDir/composite_dic12_3
echo "" 1>> ./codeLineDir/composite_dic12_3

done
echo 'sjisTextToUtf8Code01_dic12_3 終了' 1>&2
return 0
}


: << '#--------------------------------------------------------------comment'
 12_1 は単独で実行し、中間ファイルを作成する。
 12_2 は単独で実行し、12_1が作った中間ファイルから、さらに中間ファイルを作成する。
 12_3 は単独で実行し、12_2が作った中間ファイルから、完成ファイルを作成する。
 連続で実行しても構わない。
 テストで作成した古いファイルが残っている場合は、すべて削除してから実行する。
 中間ファイルは使用後に削除しても構わない。
#--------------------------------------------------------------comment

sjisTextToUtf8Code01_dic12_1
sjisTextToUtf8Code01_dic12_2
sjisTextToUtf8Code01_dic12_3


exit 0

sjisTextToUtf8Code01_dic13.sh

#!/bin/sh
#set -x
: << '#--------------------------------------------------------------comment'
■10進数処理用辞書作成スクリプト
〜utf8 16進数コード、連続変数代入の複合辞書版

▼用意するデータファイル
別スクリプトで作成した辞書ファイル2個
	・composite_dic11_3
	ef bc 9a, ef bc 9b, ef bc 9f, ef bc 81, e3 82 9b, 
	・composite_dic12_3
	u256_125=" 7d"; u256_126=" 7e"; u256_161=" ef bd a1"; u256_162=" ef bd a2";


▼処理
行の一部を入れ替える。
一瞬で終わる。

▼行の内訳

001 カンマ区切りcsv

128 カンマ区切りcsv
129 変数代入式 セミコロン区切り

152 変数代入式 セミコロン区切り
153 カンマ区切りcsv

255 カンマ区切りcsv
256 変数代入式 セミコロン区切り


▼使用方法

実行)辞書作成中間ファイル作成スクリプトcp932dicMaker1.sh
   ↓
実行)sjisTextToUtf8Code01_dic11.sh
実行)sjisTextToUtf8Code01_dic12.sh

生成ファイル
「composite_dic11_3,composite_dic12_3」が入ったディレクトリを指定して、
このスクリプトを実行する

上記のスクリプトを実行した時点で、
「./codeLineDir/」が生成されているはず。

#--------------------------------------------------------------comment


sjisTextToUtf8Code01_dic13_1(){

# 辞書の元になるテキストファイル、
# composite_dic11_3,composite_dic12_3が入ったディレクトリ
# 最後にスラッシュをつけること
dir="./codeLineDir/"

cd "${dir}"
if test "${?}" -ne 0 ;then exit 1 ;fi
if ls composite_dic11_3 ;then true ;else exit 1 ;fi
if ls composite_dic12_3 ;then true ;else exit 1 ;fi

echo "1〜128" 1>&2
0< composite_dic11_3 head --lines="128" 1> ./nukamisoCP932decToUTF8hex_05.txt
echo "129〜152" 1>&2
0< composite_dic12_3 head --lines="152" | tail --lines="24" 1>> ./nukamisoCP932decToUTF8hex_05.txt
echo "153〜255" 1>&2
0< composite_dic11_3 head --lines="255" | tail --lines="103" 1>> ./nukamisoCP932decToUTF8hex_05.txt
echo "256" 1>&2
0< composite_dic12_3 tail --lines="1" 1>> ./nukamisoCP932decToUTF8hex_05.txt

echo "おわり" 1>&2
return 0
}


########################################################################
# 最初から最後まで通して実行するのに必要なファイルのリスト
# これら6ファイルを、同じディレクトリに置く
#
# cp932CharMaker3.sh (cp932の1バイト文字を作成)
# cp932CharMaker4.sh (cp932の2バイト文字を作成)
# cp932dicMaker1.sh (辞書作成中間ファイル作成スクリプト)
#
# sjisTextToUtf8Code01_dic11.sh (10進辞書 utf8-16進)
# sjisTextToUtf8Code01_dic12.sh (10進辞書 utf8-16進 変数代入式)
# sjisTextToUtf8Code01_dic13.sh (あなたが見ているこのファイル)
#
# まとめて自動実行するなら、↓をコメントアウトする
# 無駄コードは、あってもなくても、結果は同じ。
########################################################################


#: << '#--------------------------------------------------------------exe'
# ------最初の最初から実行するなら-----------
# cp932のテキストファイル作成から実行するならコメントアウト
./cp932dicMaker1.sh
#--------------------------------------------------------------exe
#: << '#--------------------------------------------------------------exe'
# 整理整頓ができるかどうか試す、無駄コード
0< cp932hex-utf8hex.txt shuf > temp.${$}
rm cp932hex-utf8hex.txt
mv temp.${$} cp932hex-utf8hex.txt
#--------------------------------------------------------------exe
#: << '#--------------------------------------------------------------exe'
# ------「cp932hex-utf8hex.txt」がディレクトリに作成済みの時点から------
# まとめて実行するならコメントアウト
./sjisTextToUtf8Code01_dic11.sh &
./sjisTextToUtf8Code01_dic12.sh
wait
#--------------------------------------------------------------exe
sjisTextToUtf8Code01_dic13_1



exit 0

テキストファイル変換スクリプト本体 [sjisTextToUtf8Code02.sh]

#!/bin/sh
#set -x
: << '#--------------------------------------------------------------comment'
■cp932テキストファイルを、utf8コードに変換する。(odコマンドから変換する)
・処理の中心はodコマンド,echoコマンド,変換データの辞書。
・cp932テキストを入力すると、utf8バイナリコードが出力される。
・改行文字[0d0a][0a]、タブ[09]に対応。出力の改行は「0a」となる。
・「0d」改行には非対応
・辞書はテキストファイルで一つのみ

▼ バイナリを読むコマンドのオプション
【10進数】で出力する。
od --endian=big --address-radix=n --format u1 --output-duplicates --width=64 |
hexdump -v -e '16/1 " %03u"' -e '"\n"' |

▼辞書ファイル
別スクリプトで作成
 u147_69=" e6 91 98"; u147_70=" e6 93 a2"; u147_71=" e6 95 b5";
 e8 8d bf, e8 8f 87, e8 8f b6, e8 91 88, e8 92 b4, 
「uft8-16進数」と「utf8-16進数変数代入式」の複合辞書
 
 
▼処理
utf8テキスト出力版(printf使用版)とほぼ同様。
こちらはprintfを使わず、echoで出力する。


▼使用例、出力データ形式
$ cat _iroha-sjis.txt |./sjisTextToUtf8Code01.sh 
 30 31 32 33 0a 09 09 74 61 62 0a 20 20 20 20 20 20 20 20 20 20 73 70 0a e8 89 b2 e3 81 af e5
 8c 82 e3 81 b8 e3 81 a9 20 e6 95 a3 e3 82 8a e3 81 ac e3 82 8b e3 82 92 0a e6 88 91 20 e3 81
 8c 20 e4 b8 96 20 e8 aa b0 20 e3 81 9e 20 e5 b8 b8 20 e3 81 aa 20 e3 82 89 20 e3 82 80 0a e6
 9c 89 e7 82 ba e3 81 ae e5 a5 a5 e5 b1 b1 20 20 e4 bb 8a e6 97 a5 e8 b6 8a e3 81 88 e3 81 a6
 0a e6 b5 85 e3 81 8d e5 a4 a2 e8 a6 8b e3 81 98 e3 80 80 e3 80 80 e9 85 94 e3 81 b2 e3 82 82
 e3 81 9b e3 81 9a


▼速度比較 (printf版と異なりkshでも速い)
$ time cat gulliver_ryokoki.txt | dash ./sjisTextToUtf8Code02.sh 1>/dev/null
real	0m5.933s
user	0m4.596s
sys	0m1.936s

$ time cat gulliver_ryokoki.txt | bash ./sjisTextToUtf8Code02.sh 1>/dev/null
real	0m24.262s
user	0m22.893s
sys	0m2.436s

$ time cat gulliver_ryokoki.txt | ksh ./sjisTextToUtf8Code02.sh 1>/dev/null
real	0m8.687s
user	0m8.470s
sys	0m1.082s

#--------------------------------------------------------------comment

sjisTextToUtf8Code02(){

# 複合辞書のパス
dict="./dic/nukamisoCP932decToUTF8hex_05.txt"


# 予め辞書から変数に代入する文字列:1バイト文字 ASCII、半角カタカナ
eval `0< "${dict}" sed -n 256p `

od --endian=big --address-radix=n --format u1 --output-duplicates --width=64 |
#hexdump -v -e '16/1 " %03u"' -e '"\n"' |

while read line ;do
for dec in ${line} ;do
if test -n "${doubleDec}" ;then # ------------------------2バイト文字を出力

	# 辞書を読み込んだら変数に代入しておく
	eval 'if test -z "${u'${doubleDec}_${dec}'}" ;then \
	u'${doubleDec}_${dec}'="`< ${dict} sed -n ${doubleDec}p | cut -d , -f ${dec}`" ;fi'
	eval 'echo -n "${u'${doubleDec}_${dec}'}"'

	doubleDec=""


elif test \(  32 -le ${dec} -a ${dec} -le 126 \) -o \
           \( 161 -le ${dec} -a ${dec} -le 223 \) -o \
            ${dec} -eq 9 -o ${dec} -eq 10 ; then  # ---------1バイト文字を出力
	# 事前に代入した変数で出力 
	eval 'echo -n "${u256_'${dec}'}"'


# 0x8140「 」〜0x98fc「傲」
elif test  129 -le ${dec} -a ${dec} -le 152 ;then 
doubleDec="${dec}" # ------頻出2バイト文字の上位バイトを変数に格納して次バイトと繋ぐ

# 読み込み済みの辞書行を点検
eval 'dicLineCheck=${dicLine'${dec}'}' # evalでcase文を括らないために
case "${dicLineCheck}"0 in
( @ ) true ;;
( 0 )
	eval `0< "${dict}" sed -n ${dec}p`
	eval 'dicLine'${dec}'=@'
;;
esac



else # 「elif test 〜」しなくても、elseで動いてしまう
#elif test \( 153 -le ${dec} -a ${dec} -le 159 \) -o \
#           \( 224 -le ${dec} -a ${dec} -le 252 \) -o \
#            ${dec} -eq 13 ;then # ------2バイト文字の上位バイトを変数に格納
doubleDec="${dec}"

fi ; done ; done | fmt --width=96 --goal=96
}



sjisTextToUtf8Code02

exit 0

完成した辞書ファイル[nukamisoCP932decToUTF8hex_05.txt]の一部

大きすぎてブログがエラーになりました。サンプルだけ載せときます。

,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,, e9 ab 9c, e9 ad b5, e9 ad b2, e9 ae 8f, e9 ae b1, e9 ae bb, e9 b0 80, e9 b5 b0, e9 b5 ab, ef a8 ad, e9 b8 99, e9 bb 91,



u256_9=" 09"; u256_10=" 0a"; u256_32=" 20"; u256_33=" 21"; u256_34=" 22"; u256_35=" 23"; u256_36=" 24"; u256_37=" 25"; u256_38=" 26"; u256_39=" 27";