初歩のシェルスクリプトで遊ぶ[シフトJISをutf8に変換-3,メガネハナーンを6226個に切り刻む]
調べものには使えません。
Ubuntu18.04,Virtualbox6.1.2,dash,bash
端末の平仮名をバラす
$ echo -n あ | od -An -tx1 e3 81 82
「あ」をechoし、odに読ませると、「e3 81 82」と出ます。
$ echo -n あ 1>あ.txt $ 0< あ.txt od -tx1 0000000 e3 81 82 0000003
「あ」をファイルにリダイレクトして、ファイルをodで読んでも、同じく「e3 81 82」。普通にエディタでも「あ」と読める、正しいテキストファイルが作れる。
$ cat あ.txt | head --bytes=1 > e3.file $ 0< e3.file od -tx1 0000000 e3 0000001
「あ.txt」の1バイト目だけheadコマンドで切り取り、ファイルを作ると、「e3」だけになった。
$ 0< あ.txt head --bytes=2 | tail --bytes=1 > 81.file $ 0< あ.txt head --bytes=3 | tail --bytes=1 > 82.file
同様に2バイト目、3バイト目をファイルにして、
$ cat e3.file 81.file 82.file あ
「e3 81 82」の順にcatすると、「あ」と表示された。(実際に端末で実行すると改行なしで表示される)
catコマンドで「あ」と表示するには、「e3 81 82」と書かれた3バイトのファイルでなくてもよい。
「e3」と「81」と「82」の3ファイルでも構わない。
次に、同じように「や」でファイルを作る。「e3 82 84」だから、重複しない「84」を。
$ echo -n や > や.txt $ echo -n や | head --bytes=3 | tail --bytes=1 > 84.file $ ls 81.file 82.file 84.file e3.file あ.txt や.txt
元は「あ」と「や」だったファイルを、違う組み合わせでcatする、と?
$ cat e3.file 81.file 84.file い $ cat e3.file 82.file 81.file め $ cat e3.file 82.file 82.file も $ cat e3.file 81.file 81.file ぁ $ cat e3.file 81.file 82.file e3.file 82.file 84.file e3.file 81.file 84.file >あやい.txt $ cat あやい.txt あやい $ cat あやい.txt | od -tx1 0000000 e3 81 82 e3 82 84 e3 81 84 0000011
元の文字とは違う文字を、作ることができる。もちろんファイルにリダイレクトすることもできる。同じバイトを複数使っても構わない。
ここまでで、ごく小さなテキストファイルなら、catコマンドは1バイト単位で作れる、と分かった。
私はこんな使い方が想定されてるかなんて知りません。膨大な数はダメだとか、特定の文字しか作れないとか、環境依存とか、私には分かりませんが。
しかし、この前に7000個のファイルをcatコマンドで繋げ続けて、『ガリバー旅行記』を作ってみても、テキストエディタで作った正しいファイルとmd5が一致する、ということまでは分かってたわけです。
catコマンドは、人間が読むテキストファイルを連結したり、何ギガバイトもある大きなファイルを結合する、というもんだと思ってたのだけど。1バイト単位でも、やらせればできる、ってことは分かった。
catコマンドが悲鳴あげてるかもしれんけど。
256個のファイルがあれば、どんなファイルでも作れる?
「1バイトのファイル」は、多くても256種類あればいい。00〜FFまでなのだから。
もちろん全部を使える保証なんて無い。「00」だけ使えないとか、ありそうだ。しかしテキストファイルなら不要なバイトもあるだろう。7800個の辞書ファイルは、数を減らせるはず。
もし256種類使えたら?
テキストファイルだけでなく、「任意のファイルを作れるんじゃないの?」と考えたくなります。
1バイトのファイルをどうやって作るか
もちろん手段はいろいろ有るに決まっているのだけれど、私は他の言語も含めて知りません。xxdコマンドも知らなかった。echoやprintfでバイナリを作るのも、まだ調べてもいない。
Windowsのバイナリエディタか何かを使うことも検討したけど、自分ができる範囲で、シェルスクリプトで考えたかった。
このとき思いついたのは、「小さなファイルをcatで組み合わせて大きなファイルを作る」のだから、逆に「大きなファイルを分割して小さくすれば、1バイトになるんじゃないの?」というもの。
模範解答をネットで探すより、手段があるなら作ったほうが早い。
メガネハナーンを6226個に切り刻む
cp932のテキストファイルをodコマンドで調べると、222種類と、だいぶ足りません。1バイトファイルの材料にはなりませんが、逆に、256種類なくてもテキストファイルなら作れる可能性はある、とわかった。
10年前の、メガネハナーンの落書きがありました。6226バイトのPNG画像です。
↑(注:この画像、アップロードしたら容量増えました。万一試すなら、お手元の手ごろな画像ファイルつかってください。)
cat hanamegane.png | od -An -v -tx1 | tr " " "\n" | sort | uniq -c |wc
odコマンドで調べると、256種類揃っていた。メガネハナーンを材料にします。
0< splitFile.temp split --bytes=1
要点はココ。splitコマンドは、1バイトの指定でも受け付けてくれた。
作ったスクリプトは以下。
byteCellGenerator_02.sh
#!/bin/sh #set -x : << '#--------------------------------------------------------------comment' ■1バイトファイル作成スクリプト メガネハナーンを千切りにして、1バイトのファイルを256種類生成する。 byteCellGenerator_02_01(){ # 作業場所の確認、実行の確認 byteCellGenerator_02_02(){ # ファイルを1バイト1ファイルに切り刻む byteCellGenerator_02_03(){ # 1バイトファイルの中身を調べて名前変更する,重複を削除する #--------------------------------------------------------------comment # 設定 byteFileOutDir="./byteCellTemp/" # ファイルを置くディレクトリを指定する sengiriFile="./hanamegane.png" # 切り刻み元のファイルを指定。せいぜい7000バイト程度に! byteCellGenerator_02_01(){ # 作業場所の確認、実行の確認 # 作成するファイルの置き場所 mkdir "${byteFileOutDir}" 2>/dev/null if mkdir "${byteFileOutDir}check/" ;then # 試しに作成先に、ディレクトリを作成してみる rmdir "${byteFileOutDir}check/" else # 作れなかったら終了 echo 作成先ディレクトリを確認 ;exit 1 fi # 切り刻むファイル sengiriFileSize=`cat "${sengiriFile}" | wc -c` echo "${sengiriFileSize}"byte if test 0${sengiriFileSize} -lt 6500 ;then #最大ファイルサイズの制限 : else echo '終了する' exit fi # 実行確認 echo "${byteFileOutDir}:作成先ディレクトリ" echo "${sengiriFileSize}:生成予定ファイル数" echo '[y]実行 [*]終了' read action case $action in ( y ) true ;; ( * ) echo '終了する' ;exit 0 ;; esac } byteCellGenerator_02_02(){ # ファイルを1バイト1ファイルに切り刻む cp "${sengiriFile}" "${byteFileOutDir}"/splitFile.temp ( cd "${byteFileOutDir}" # 「--bytes=1」は、まず「--bytes=1000」以上でテストすること 0< splitFile.temp split --bytes=1 --numeric-suffixes=0 --suffix-length=6 --additional-suffix=".chip" --verbose ) rm "${byteFileOutDir}"/splitFile.temp if test ${?} -ne 0 ;then exit else true fi } # 1バイトファイルの中身を調べて名前変更する, # 同一内容のファイルを上書きしてゆき、256種類以下に減らす byteCellGenerator_02_03(){ ( cd ${byteFileOutDir} # mvでリネームと上書きをするためにcdする sengiriChipS="`echo *.chip`" chipCount=`echo ${sengiriChipS} | wc -w ` echo ${chipCount}:ファイル数 # 実行確認 echo 'ファイルを検査、リネーム、重複削除' echo '[y]実行 [*]終了' read action case $action in ( y ) true ;; ( * ) echo '終了する' ;exit 0 ;; esac # 主処理 for chip in ${sengiriChipS} ;do chipHex=`od -An -tx1 -v "${chip}"` mv -v "${chip}" ${chipHex} done ls echo `ls | wc -w`" 種類" ) } byteCellGenerator_02_01 byteCellGenerator_02_02 byteCellGenerator_02_03 exit 0
実行結果
renamed 'x006219.chip' -> '45' renamed 'x006220.chip' -> '4e' renamed 'x006221.chip' -> '44' renamed 'x006222.chip' -> 'ae' renamed 'x006223.chip' -> '42' renamed 'x006224.chip' -> '60' renamed 'x006225.chip' -> '82' 00 09 12 1b 24 2d 36 3f 48 51 5a 63 6c 75 7e 87 90 99 a2 ab b4 bd c6 cf d8 e1 ea f3 fc 01 0a 13 1c 25 2e 37 40 49 52 5b 64 6d 76 7f 88 91 9a a3 ac b5 be c7 d0 d9 e2 eb f4 fd 02 0b 14 1d 26 2f 38 41 4a 53 5c 65 6e 77 80 89 92 9b a4 ad b6 bf c8 d1 da e3 ec f5 fe 03 0c 15 1e 27 30 39 42 4b 54 5d 66 6f 78 81 8a 93 9c a5 ae b7 c0 c9 d2 db e4 ed f6 ff 04 0d 16 1f 28 31 3a 43 4c 55 5e 67 70 79 82 8b 94 9d a6 af b8 c1 ca d3 dc e5 ee f7 05 0e 17 20 29 32 3b 44 4d 56 5f 68 71 7a 83 8c 95 9e a7 b0 b9 c2 cb d4 dd e6 ef f8 06 0f 18 21 2a 33 3c 45 4e 57 60 69 72 7b 84 8d 96 9f a8 b1 ba c3 cc d5 de e7 f0 f9 07 10 19 22 2b 34 3d 46 4f 58 61 6a 73 7c 85 8e 97 a0 a9 b2 bb c4 cd d6 df e8 f1 fa 08 11 1a 23 2c 35 3e 47 50 59 62 6b 74 7d 86 8f 98 a1 aa b3 bc c5 ce d7 e0 e9 f2 fb 256 種類
いけました。
組み立てる
入力データに従って、ファイルを組み立てます。
入力の規格は、以下のodコマンドの出力と同じ、とします。
$ echo あいうえおかきくけこ | od -An -tx1 -v e3 81 82 e3 81 84 e3 81 86 e3 81 88 e3 81 8a e3 81 8b e3 81 8d e3 81 8f e3 81 91 e3 81 93 0a
組み立てるスクリプトは、最小限ならこれだけで済みます。
・while-read版
# 1バイトの組み立て部品ファイル置き場 byteCellDir="./byteCell0x/" cd "${byteCellDir}" while read byteLine ;do eval cat ${byteLine} done
1バイトファイルの入ったディレクトリに移動して、「e3 81 82 e3 81 84 e3 81 86 e3 81 88 e3 81 8a e3」~の文字列を、1行ずつcatするだけ。
1バイトファイルのファイル名を、中身と同じ16進数にしています。
こうすると、入力文字列を加工もせずに、catコマンドにまとめて渡すだけで、数字そのままのバイナリをcatし続けることができる。とても単純。
(evalはzshのために入れてます。bashやdashなら、要りません。)
・xargs版
# 1バイトの組み立て部品ファイル置き場 byteCellDir="./byteCell0x/" cd "${byteCellDir}" xargs cat
実際に組むときは、もうちょい追加すると性能が出ます。
#!/bin/sh #set -x : << '#--------------------------------------------------------------comment' ■ 1バイトのファイルを組み合わせて、任意のファイルを作成する〜「while read」版 ▼ 手順 1)「00〜ff」256種類の1バイトファイルを用意する。 2)これら1バイトファイルから、catコマンドで結合ファイルを作成する。 3)入力データは、16進数を並べたテキストデータとする。 ▼ 入力16進数文字列を、そのままcatコマンドの引数に使う 1バイトファイル名を、中身と同名の16進数のみにする。拡張子などは付けない。 入力データを、そのまま引数としてcatコマンドに渡す。 1バイトずつcatを実行するのではなく、1行分、下記では16バイトずつ実行する。 xargsでも同じ処理を書けるはずだが、それはそれ。 ▼ odコマンドの出力に限定する od --endian=big --address-radix=n --format x1 --output-duplicates e8 b5 a4 e5 b7 bb e7 b4 99 e9 9d 92 e5 b7 bb e7 b4 99 e9 bb 84 e5 b7 bb e7 b4 99 0a ・16進数、1バイトずつ、空白区切り。 ・改行が必要。16バイトずつ程度だが、増減は許容すべき。 ▼速度 $ time cat gulliver-utf8Code02.txt | dash ./binCreator_02.sh >/dev/null real 0m5.074s user 0m2.030s sys 0m2.915s #--------------------------------------------------------------comment # 1バイトの組み立て部品ファイル置き場 byteCellDir="./byteCell0x/" binaryCreator_02(){ : << '#--------------------------------------------------------------comment' 「eval cat」のevalは、zshへの対応。 「tr,sed」の行は、入力の対応の拡大と、高速化。削除しても動作する。 1行を長くすると、高速になる。もちろん限度はある。 行の折り返しはfoldかfmtで行う。 foldは「-s」が必要。終端に改行がつかない。改行のない最終行が失われることを 防ぐため、whileループと直後の「eval cat」をサブシェルの括弧で括る。 #--------------------------------------------------------------comment cd "${byteCellDir}" tr -d " " | tr -d "\n" | sed -e 's/../ &/g;y/ABCDEF/abcdef/' | fold -s -w 1200 | ( while read byteLine ;do eval cat ${byteLine} done eval cat ${byteLine} ) } : << '#------------------------------test' echo -n " e8 b5 a4 e5 b7 bb e7 b4 99 e9 9d 92 e5 b7 bb e7 b4 99 e9 bb 84 e5 b7 bb e7 b4 99 0a " | #------------------------------test binaryCreator_02 exit 0
追加で試験しました。WindowsのFirefoxの、setup.exe。
$ time 0< ./FirefoxSetup72.0.2.exe od -An -v -tx1 | dash ./binCreator_02.sh >FirefoxSetup72.0.2.exe_copy real 15m8.692s user 4m25.774s sys 10m24.367s $ md5sum FirefoxSetup72.0.2.exe* c583a5b233a03141a5308afa8019f76b FirefoxSetup72.0.2.exe c583a5b233a03141a5308afa8019f76b FirefoxSetup72.0.2.exe_copy
いけますね。バイナリファイルでも。
#!/bin/sh #set -x : << '#--------------------------------------------------------------comment' ■1バイトのファイルを組み合わせて、任意のファイルを作成する〜「xargs」版 xargsに書き換えて、while-readループを排除する。引数の数の調整なども任せる。 xargsでも、改行のない最終行は、処理できるようだ。 ・xargs cat $ time cat gulliver-utf8Code02.txt | ./binaryCreator_03.sh >/dev/null real 0m3.001s user 0m0.931s sys 0m1.952s ・tr -d "\n" | xargs -d " " -I @@ cat @@ $ time cat gulliver-utf8Code02.txt | ./binaryCreator_03.sh >/dev/null real 5m59.764s user 4m18.513s sys 0m55.739s #--------------------------------------------------------------comment # 1バイトの組み立て部品ファイル置き場 byteCellDir="./byteCell0x/" binaryCreator_03_01(){ ( cd "${byteCellDir}" xargs cat ) } : << '#------------------------------test' echo -n " e8 b5 a4 e5 b7 bb e7 b4 99 e9 9d 92 e5 b7 bb e7 b4 99 e9 bb 84 e5 b7 bb e7 b4 99 0a " | #------------------------------test binaryCreator_03_01 exit 0
任意のファイルを作れるのなら、テキストファイルだって作れる
16進数の文字列から、ファイルを作れるようになった。
16進数でなくても、10進数でもいい。ファイル名を変えるだけでいいから。
これはこれで纏めるとして、元の目的に戻ります。cp932のテキストファイルをodコマンドで読み、utf8に変換するには、どうしたらいいか。
結局は先のエントリに載せた、直接に文字をpritfで出力するのが比較的マシだったのだけど、utf8の16進数からテキストファイルに変換するのもやりました。
utf8の16進数にしておけば、別の文字コードにも変えられるだろうし、これはこれでアリだろう。
1バイトファイル方式、気に入ってはいるんすよ。ローテクで。
是非とも、メガネハナーンの切れ端を濃縮したファイルを使いたい。……ああ、これがホメオパシーというものか。なるほど。
つづく。
もうちょい正気なスクリプト
これ、バイナリファイルを、シェルで作るにはどうしたらいいのか、の初歩テストなんだと思います、たぶん。
1バイトファイルの作成スクリプト(そこそこ普通のもの)
#!/bin/sh #set -x : << '#--------------------------------------------------------------comment' ■1バイトファイルの自動作成スクリプト 00〜ffの、256種類の1バイトファイルを作成する _1) xxdコマンド版 _2) 「echo -en "\x??"」版 _3) 「echo -n "\0???"」版 _4) 「printf "\???"」版 xxdコマンドに変換してもらうと簡単だし、 printfならdashでも「00」を出力できるみたい。 #--------------------------------------------------------------comment # 共通設定 byteCellGenerator01_comp(){ # 作成するファイルの置き場所 outDir="./byteCellTemp/" if test -d "${outDir}" ;then true else exit 1;fi echo "保存先: ${outDir}" ;ls "${outDir}" ; echo "実行[y] | やめる [*]" read action if test ${action} = y ;then true else exit 0 ;fi } byteCellGenerator01_1(){ # xxdコマンド版 dash,bash,zsh,ksh # 16進数 00〜FF アルファベット大文字 hexSeq="00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F 10 11 12 13 14 15 16 17 18 19 1A 1B 1C 1D 1E 1F \ 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 7F \ 80 81 82 83 84 85 86 87 88 89 8A 8B 8C 8D 8E 8F 90 91 92 93 94 95 96 97 98 99 9A 9B 9C 9D 9E 9F \ A0 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 \ E0 E1 E2 E3 E4 E5 E6 E7 E8 E9 EA EB EC ED EE EF F0 F1 F2 F3 F4 F5 F6 F7 F8 F9 FA FB FC FD FE FF" # 16進数 00〜ff アルファベット小文字に変換 # ファイル名を大文字にするならコメントアウト hexSeq=`echo "${hexSeq}" | tr A-F a-f ` eval 'for byte in '${hexSeq}' ; do \ echo -n ${byte} | xxd -r -p > "${outDir}${byte}" ; \ done' ls "${outDir}" } byteCellGenerator01_2(){ # 「echo -en "\x??"」版 使用可:bash,zsh,ksh 不可:dash # 16進数の00〜ffを作成 hexSeq=` seq 0 255 | xargs -I @@ echo 'obase=16;ibase=10;@@' | bc | sed '1,16s/./0&/' | tr A-F a-f ` echo "${hexSeq}" | while read hex ;do echo -en "\x${hex}" > ${outDir}${hex} done ls "${outDir}" } : << '#--------------------------------------------------------------comment' dash用に8進数指定で作ったが、「00」が作れない。 bashは「echo -en」とする必要がある。 使いみちがない。 #--------------------------------------------------------------comment byteCellGenerator01_3(){ # 「echo -n "\0???"」版 使用可:zsh,ksh 不可:dash,bash for n in `seq 0 255`;do OCT=`echo ${n} | xargs -I @@ echo 'obase=8;ibase=10;@@' | bc ` HEX=`echo "obase=16;ibase=10;${n}" | bc | sed 's/./0&/;s/0\(..\)/\1/;y/ABCDEF/abcdef/' ` eval 'echo -n "\0'${OCT}'" > ${outDir}${HEX}' # bash用 #eval 'echo -en "\0'${OCT}'" > ${outDir}${HEX}' done ls "${outDir}" } byteCellGenerator01_4(){ # 「printf "\???"」版 使用可:dash,bash,ksh,zsh for n in `seq 0 255`;do OCT="`printf "%03o" ${n}`" HEX="`printf "%02x" ${n}`" eval 'printf "\'${OCT}'" > ${outDir}${HEX}' done ls "${outDir}" } # 共通 byteCellGenerator01_comp # どれか一つ #byteCellGenerator01_1 #byteCellGenerator01_2 #byteCellGenerator01_3 byteCellGenerator01_4 exit 0
バイナリファイル作成(つまんないもの)
zshで動かないのは、forループの変数展開に配慮してないから、だったはず。あんまり気が進まなくて、サボりました。
zsh使うような詳しい人が、こんなん使うはずないし、別に構わんだろう。
#!/bin/dash #set -x : << '#--------------------------------------------------------------comment' ■ 任意のファイルを作成する〜変数代入 printf 版 ▼ 概要 ・printfで『変数に代入』する printfでバイナリデータを作り、バイナリデータを変数に格納する。 出力は主に「echo -n」で行う。 難しい「00」は、printfで行う。 ▼ シェル環境 動作する :dash,bash,ksh 動作しない:zsh $ time cat gulliver-utf8Code02.txt | dash ./binaryCreator_05.sh >/dev/null real 0m2.998s user 0m1.877s sys 0m1.095s $ time cat gulliver-utf8Code02.txt | bash ./binaryCreator_05.sh >/dev/null real 0m12.197s user 0m10.855s sys 0m1.315s #--------------------------------------------------------------comment binaryCreator_05_01(){ #HEX00="` printf '\000' `"; HEX01="` printf '\001' `"; HEX02="` printf '\002' `"; HEX03="` printf '\003' `"; HEX04="` printf '\004' `"; HEX05="` printf '\005' `"; HEX06="` printf '\006' `"; HEX07="` printf '\007' `"; HEX08="` printf '\010' `"; HEX09="` printf '\011' `"; HEX0a="` printf '\012' `"; HEX0b="` printf '\013' `"; HEX0c="` printf '\014' `"; HEX0d="` printf '\015' `"; HEX0e="` printf '\016' `"; HEX0f="` printf '\017' `"; HEX10="` printf '\020' `"; HEX11="` printf '\021' `"; HEX12="` printf '\022' `"; HEX13="` printf '\023' `"; HEX14="` printf '\024' `"; HEX15="` printf '\025' `"; HEX16="` printf '\026' `"; HEX17="` printf '\027' `"; HEX18="` printf '\030' `"; HEX19="` printf '\031' `"; HEX1a="` printf '\032' `"; HEX1b="` printf '\033' `"; HEX1c="` printf '\034' `"; HEX1d="` printf '\035' `"; HEX1e="` printf '\036' `"; HEX1f="` printf '\037' `"; HEX20="` printf '\040' `"; HEX21="` printf '\041' `"; HEX22="` printf '\042' `"; HEX23="` printf '\043' `"; HEX24="` printf '\044' `"; HEX25="` printf '\045' `"; HEX26="` printf '\046' `"; HEX27="` printf '\047' `"; HEX28="` printf '\050' `"; HEX29="` printf '\051' `"; HEX2a="` printf '\052' `"; HEX2b="` printf '\053' `"; HEX2c="` printf '\054' `"; HEX2d="` printf '\055' `"; HEX2e="` printf '\056' `"; HEX2f="` printf '\057' `"; HEX30="` printf '\060' `"; HEX31="` printf '\061' `"; HEX32="` printf '\062' `"; HEX33="` printf '\063' `"; HEX34="` printf '\064' `"; HEX35="` printf '\065' `"; HEX36="` printf '\066' `"; HEX37="` printf '\067' `"; HEX38="` printf '\070' `"; HEX39="` printf '\071' `"; HEX3a="` printf '\072' `"; HEX3b="` printf '\073' `"; HEX3c="` printf '\074' `"; HEX3d="` printf '\075' `"; HEX3e="` printf '\076' `"; HEX3f="` printf '\077' `"; HEX40="` printf '\100' `"; HEX41="` printf '\101' `"; HEX42="` printf '\102' `"; HEX43="` printf '\103' `"; HEX44="` printf '\104' `"; HEX45="` printf '\105' `"; HEX46="` printf '\106' `"; HEX47="` printf '\107' `"; HEX48="` printf '\110' `"; HEX49="` printf '\111' `"; HEX4a="` printf '\112' `"; HEX4b="` printf '\113' `"; HEX4c="` printf '\114' `"; HEX4d="` printf '\115' `"; HEX4e="` printf '\116' `"; HEX4f="` printf '\117' `"; HEX50="` printf '\120' `"; HEX51="` printf '\121' `"; HEX52="` printf '\122' `"; HEX53="` printf '\123' `"; HEX54="` printf '\124' `"; HEX55="` printf '\125' `"; HEX56="` printf '\126' `"; HEX57="` printf '\127' `"; HEX58="` printf '\130' `"; HEX59="` printf '\131' `"; HEX5a="` printf '\132' `"; HEX5b="` printf '\133' `"; HEX5c="` printf '\134' `"; HEX5d="` printf '\135' `"; HEX5e="` printf '\136' `"; HEX5f="` printf '\137' `"; HEX60="` printf '\140' `"; HEX61="` printf '\141' `"; HEX62="` printf '\142' `"; HEX63="` printf '\143' `"; HEX64="` printf '\144' `"; HEX65="` printf '\145' `"; HEX66="` printf '\146' `"; HEX67="` printf '\147' `"; HEX68="` printf '\150' `"; HEX69="` printf '\151' `"; HEX6a="` printf '\152' `"; HEX6b="` printf '\153' `"; HEX6c="` printf '\154' `"; HEX6d="` printf '\155' `"; HEX6e="` printf '\156' `"; HEX6f="` printf '\157' `"; HEX70="` printf '\160' `"; HEX71="` printf '\161' `"; HEX72="` printf '\162' `"; HEX73="` printf '\163' `"; HEX74="` printf '\164' `"; HEX75="` printf '\165' `"; HEX76="` printf '\166' `"; HEX77="` printf '\167' `"; HEX78="` printf '\170' `"; HEX79="` printf '\171' `"; HEX7a="` printf '\172' `"; HEX7b="` printf '\173' `"; HEX7c="` printf '\174' `"; HEX7d="` printf '\175' `"; HEX7e="` printf '\176' `"; HEX7f="` printf '\177' `"; HEX80="` printf '\200' `"; HEX81="` printf '\201' `"; HEX82="` printf '\202' `"; HEX83="` printf '\203' `"; HEX84="` printf '\204' `"; HEX85="` printf '\205' `"; HEX86="` printf '\206' `"; HEX87="` printf '\207' `"; HEX88="` printf '\210' `"; HEX89="` printf '\211' `"; HEX8a="` printf '\212' `"; HEX8b="` printf '\213' `"; HEX8c="` printf '\214' `"; HEX8d="` printf '\215' `"; HEX8e="` printf '\216' `"; HEX8f="` printf '\217' `"; HEX90="` printf '\220' `"; HEX91="` printf '\221' `"; HEX92="` printf '\222' `"; HEX93="` printf '\223' `"; HEX94="` printf '\224' `"; HEX95="` printf '\225' `"; HEX96="` printf '\226' `"; HEX97="` printf '\227' `"; HEX98="` printf '\230' `"; HEX99="` printf '\231' `"; HEX9a="` printf '\232' `"; HEX9b="` printf '\233' `"; HEX9c="` printf '\234' `"; HEX9d="` printf '\235' `"; HEX9e="` printf '\236' `"; HEX9f="` printf '\237' `"; HEXa0="` printf '\240' `"; HEXa1="` printf '\241' `"; HEXa2="` printf '\242' `"; HEXa3="` printf '\243' `"; HEXa4="` printf '\244' `"; HEXa5="` printf '\245' `"; HEXa6="` printf '\246' `"; HEXa7="` printf '\247' `"; HEXa8="` printf '\250' `"; HEXa9="` printf '\251' `"; HEXaa="` printf '\252' `"; HEXab="` printf '\253' `"; HEXac="` printf '\254' `"; HEXad="` printf '\255' `"; HEXae="` printf '\256' `"; HEXaf="` printf '\257' `"; HEXb0="` printf '\260' `"; HEXb1="` printf '\261' `"; HEXb2="` printf '\262' `"; HEXb3="` printf '\263' `"; HEXb4="` printf '\264' `"; HEXb5="` printf '\265' `"; HEXb6="` printf '\266' `"; HEXb7="` printf '\267' `"; HEXb8="` printf '\270' `"; HEXb9="` printf '\271' `"; HEXba="` printf '\272' `"; HEXbb="` printf '\273' `"; HEXbc="` printf '\274' `"; HEXbd="` printf '\275' `"; HEXbe="` printf '\276' `"; HEXbf="` printf '\277' `"; HEXc0="` printf '\300' `"; HEXc1="` printf '\301' `"; HEXc2="` printf '\302' `"; HEXc3="` printf '\303' `"; HEXc4="` printf '\304' `"; HEXc5="` printf '\305' `"; HEXc6="` printf '\306' `"; HEXc7="` printf '\307' `"; HEXc8="` printf '\310' `"; HEXc9="` printf '\311' `"; HEXca="` printf '\312' `"; HEXcb="` printf '\313' `"; HEXcc="` printf '\314' `"; HEXcd="` printf '\315' `"; HEXce="` printf '\316' `"; HEXcf="` printf '\317' `"; HEXd0="` printf '\320' `"; HEXd1="` printf '\321' `"; HEXd2="` printf '\322' `"; HEXd3="` printf '\323' `"; HEXd4="` printf '\324' `"; HEXd5="` printf '\325' `"; HEXd6="` printf '\326' `"; HEXd7="` printf '\327' `"; HEXd8="` printf '\330' `"; HEXd9="` printf '\331' `"; HEXda="` printf '\332' `"; HEXdb="` printf '\333' `"; HEXdc="` printf '\334' `"; HEXdd="` printf '\335' `"; HEXde="` printf '\336' `"; HEXdf="` printf '\337' `"; HEXe0="` printf '\340' `"; HEXe1="` printf '\341' `"; HEXe2="` printf '\342' `"; HEXe3="` printf '\343' `"; HEXe4="` printf '\344' `"; HEXe5="` printf '\345' `"; HEXe6="` printf '\346' `"; HEXe7="` printf '\347' `"; HEXe8="` printf '\350' `"; HEXe9="` printf '\351' `"; HEXea="` printf '\352' `"; HEXeb="` printf '\353' `"; HEXec="` printf '\354' `"; HEXed="` printf '\355' `"; HEXee="` printf '\356' `"; HEXef="` printf '\357' `"; HEXf0="` printf '\360' `"; HEXf1="` printf '\361' `"; HEXf2="` printf '\362' `"; HEXf3="` printf '\363' `"; HEXf4="` printf '\364' `"; HEXf5="` printf '\365' `"; HEXf6="` printf '\366' `"; HEXf7="` printf '\367' `"; HEXf8="` printf '\370' `"; HEXf9="` printf '\371' `"; HEXfa="` printf '\372' `"; HEXfb="` printf '\373' `"; HEXfc="` printf '\374' `"; HEXfd="` printf '\375' `"; HEXfe="` printf '\376' `"; HEXff="` printf '\377' `"; HEX0a=' ' while read byteLine ;do for byte in ${byteLine} ;do case ${byte} in ( 00 ) printf "\000" ;; ( * ) eval 'echo -n "$HEX'${byte}'"' ;; esac done done } : << '#--------------------test' echo -n " 5c 2f e7 b3 a0 e5 91 b3 e5 99 8c 2f e3 83 95 e3 82 a9 e3 83 b3 e3 83 88 2d e3 81 af e6 a5 bd e3 81 97 e3 81 84 e3 82 88 0a " | #--------------------test binaryCreator_05_01 exit 0
#!/bin/dash #set -x : << '#--------------------------------------------------------------comment' ■ 任意のファイルを作成する〜 printf 出力版 ▼ 概要 ・printf『で出力』する。 変数に格納するのは、8進数3桁、バックスラッシュ付きの「文字列」。 当然、「\000」も格納できる。 入力文字列を変数名に変換して、printfに渡し、printfが8進数を読み取って、 対応したバイナリデータを出力する。 ▼ 特徴 ・スクリプトファイルひとつで動作可能。 ・dashで動作する。 ・bashでもけっこう速い。 ・kshでは多少遅い。 ・つまらない。 ▼ シェル環境 動作する :dash,bash,ksh,zsh $ time cat gulliver-utf8Code02.txt | bash ./binCreator_06.sh >/dev/null real 0m3.766s user 0m1.961s sys 0m1.836s #--------------------------------------------------------------comment binaryCreator_06_01(){ H00="\000"; H01="\001"; H02="\002"; H03="\003"; H04="\004"; H05="\005"; H06="\006"; H07="\007"; H08="\010"; H09="\011"; H0a="\012"; H0b="\013"; H0c="\014"; H0d="\015"; H0e="\016"; H0f="\017"; H10="\020"; H11="\021"; H12="\022"; H13="\023"; H14="\024"; H15="\025"; H16="\026"; H17="\027"; H18="\030"; H19="\031"; H1a="\032"; H1b="\033"; H1c="\034"; H1d="\035"; H1e="\036"; H1f="\037"; H20="\040"; H21="\041"; H22="\042"; H23="\043"; H24="\044"; H25="\045"; H26="\046"; H27="\047"; H28="\050"; H29="\051"; H2a="\052"; H2b="\053"; H2c="\054"; H2d="\055"; H2e="\056"; H2f="\057"; H30="\060"; H31="\061"; H32="\062"; H33="\063"; H34="\064"; H35="\065"; H36="\066"; H37="\067"; H38="\070"; H39="\071"; H3a="\072"; H3b="\073"; H3c="\074"; H3d="\075"; H3e="\076"; H3f="\077"; H40="\100"; H41="\101"; H42="\102"; H43="\103"; H44="\104"; H45="\105"; H46="\106"; H47="\107"; H48="\110"; H49="\111"; H4a="\112"; H4b="\113"; H4c="\114"; H4d="\115"; H4e="\116"; H4f="\117"; H50="\120"; H51="\121"; H52="\122"; H53="\123"; H54="\124"; H55="\125"; H56="\126"; H57="\127"; H58="\130"; H59="\131"; H5a="\132"; H5b="\133"; H5c="\134"; H5d="\135"; H5e="\136"; H5f="\137"; H60="\140"; H61="\141"; H62="\142"; H63="\143"; H64="\144"; H65="\145"; H66="\146"; H67="\147"; H68="\150"; H69="\151"; H6a="\152"; H6b="\153"; H6c="\154"; H6d="\155"; H6e="\156"; H6f="\157"; H70="\160"; H71="\161"; H72="\162"; H73="\163"; H74="\164"; H75="\165"; H76="\166"; H77="\167"; H78="\170"; H79="\171"; H7a="\172"; H7b="\173"; H7c="\174"; H7d="\175"; H7e="\176"; H7f="\177"; H80="\200"; H81="\201"; H82="\202"; H83="\203"; H84="\204"; H85="\205"; H86="\206"; H87="\207"; H88="\210"; H89="\211"; H8a="\212"; H8b="\213"; H8c="\214"; H8d="\215"; H8e="\216"; H8f="\217"; H90="\220"; H91="\221"; H92="\222"; H93="\223"; H94="\224"; H95="\225"; H96="\226"; H97="\227"; H98="\230"; H99="\231"; H9a="\232"; H9b="\233"; H9c="\234"; H9d="\235"; H9e="\236"; H9f="\237"; Ha0="\240"; Ha1="\241"; Ha2="\242"; Ha3="\243"; Ha4="\244"; Ha5="\245"; Ha6="\246"; Ha7="\247"; Ha8="\250"; Ha9="\251"; Haa="\252"; Hab="\253"; Hac="\254"; Had="\255"; Hae="\256"; Haf="\257"; Hb0="\260"; Hb1="\261"; Hb2="\262"; Hb3="\263"; Hb4="\264"; Hb5="\265"; Hb6="\266"; Hb7="\267"; Hb8="\270"; Hb9="\271"; Hba="\272"; Hbb="\273"; Hbc="\274"; Hbd="\275"; Hbe="\276"; Hbf="\277"; Hc0="\300"; Hc1="\301"; Hc2="\302"; Hc3="\303"; Hc4="\304"; Hc5="\305"; Hc6="\306"; Hc7="\307"; Hc8="\310"; Hc9="\311"; Hca="\312"; Hcb="\313"; Hcc="\314"; Hcd="\315"; Hce="\316"; Hcf="\317"; Hd0="\320"; Hd1="\321"; Hd2="\322"; Hd3="\323"; Hd4="\324"; Hd5="\325"; Hd6="\326"; Hd7="\327"; Hd8="\330"; Hd9="\331"; Hda="\332"; Hdb="\333"; Hdc="\334"; Hdd="\335"; Hde="\336"; Hdf="\337"; He0="\340"; He1="\341"; He2="\342"; He3="\343"; He4="\344"; He5="\345"; He6="\346"; He7="\347"; He8="\350"; He9="\351"; Hea="\352"; Heb="\353"; Hec="\354"; Hed="\355"; Hee="\356"; Hef="\357"; Hf0="\360"; Hf1="\361"; Hf2="\362"; Hf3="\363"; Hf4="\364"; Hf5="\365"; Hf6="\366"; Hf7="\367"; Hf8="\370"; Hf9="\371"; Hfa="\372"; Hfb="\373"; Hfc="\374"; Hfd="\375"; Hfe="\376"; Hff="\377"; tr -d " " | tr ABCDEF abcdef | tr -d "\n" | ( fold -w128 ; echo ) | sed 's/../${H&}/g' | while read byteLine ;do eval 'printf "'${byteLine}'"' done } : << '#--------------------test' echo -n " 5c 2f e7 b3 a0 e5 91 b3 e5 99 8c 2f e3 83 95 e3 82 a9 e3 83 b3 e3 83 88 2d e3 81 af e6 a5 bd e3 81 97 e3 81 84 e3 82 88 0a " | #--------------------test binaryCreator_06_01 exit 0
・追加試験
$ time 0< FirefoxSetup72.0.2.exe od -An -tx1 -v | ./binCreator_06.sh >FirefoxSetup72.0.2.exe_copy real 5m52.308s user 2m22.637s sys 3m53.581s $ md5sum FirefoxSetup72.0.2.exe* c583a5b233a03141a5308afa8019f76b FirefoxSetup72.0.2.exe c583a5b233a03141a5308afa8019f76b FirefoxSetup72.0.2.exe_copy
printfだと1バイトファイルなんて要らんし、3倍近く早いみたいだけど。面白くはないなぁ。
イヤなんすよ。「そんなことしなくても〇〇ならできますよ」は。