初歩のシェルスクリプトで遊ぶ[md5チェックサムのファイル書式を変換]

Name                                                             MD5                               Bytes
---------------------------------------------------------------  --------------------------------  ---------
omake\nukamiso-doc_beta13_changelog.txt                          44bab025a725a77604ecdacea076c899     18,809
omake\nukamiso-doc_beta13_license.txt                            8bd736f50d06dce0694a4fbdc83f46ae     13,954
omake\nukamiso-doc_html-assets\css_edelweiss.css                 d1a11d06b9a457311f94370bd5d9941d      4,251
--- 中略 ----
omake\nukamiso_konbu_beta13_0.ttf                                b9ff8a4615e43033c72442e4cb16a344  3,427,932
omake\nukamiso_otf_beta13_0.otf                                  c2387173f3cff4c803276cf9d803498d  3,693,508
omake\nukamiso_yamiyo_beta13_0.ttf                               0dc9cbf3b76eb0f46b0e9a4add67dc1a  3,758,008
omake\nukamiso__beta13_0.ttf                                     191b368a3398d710ef991e9a2e69e698  4,227,404
rnd.css                                                          8af3a7d33be50a132cf1d1a920c5a826      2,587
------------------------------------------------------------------------------------------------------------
Total  40 Files  33,387,437 Bytes

ぬかみそフォントに同梱している、zipファイルに含まれる中身のリストです。
FastHashの詳細情報 : Vector ソフトを探す!
これはWindows用の『FastHash』というソフトで作ってます。形式としては「WinCRC」というソフトに準じてるんだそうですが、そっちのほうは私は知りません。
このチェックサムファイルはWindows用ですから、Linuxのmd5sumでは使えません。
Linuxのmd5sumが出力する形式は、ファイル名とmd5値のみがあればよく、ファイルサイズは要りません。
md5sumの出力をWindowsのWinCRC形式に変換するのは情報が足りませんが、md5sum形式への変換なら、文字の並び替えでできます。

簡単なスクリプトでmd5sum用に変換できるんじゃないかな、と思ってたんだけれども、案外めんどくさかった。

#!/bin/sh
# ====================================================================================
# ■ winCRC形式チェックサムファイルを、Linuxのmd5sum用に書き換える
# 
# ・実際に使うのはwin FastHash の生成データ
# ・入力はCP932,CRLFのテキストデータ,stdin 1ファイルずつのみ
# ・出力はstdoutのみ、ファイルは作らない
# 
# ・md5とsha256に対応する
# ・空白文字がファイル名に入っても処理できる
# 
# ・nkfを使ってはならない
# ・dos2unixを使ってはいけない
# 
# 
# 
# ====================================================================================



headerFooterCrDelSh(){ (
CR="`printf '\015'`"

while read -r LINE ; do

# 行末のCRを削除
LINE="${LINE%${CR}}"

# 行末が「-」または「Bytes」の行を削除
case "${LINE}" in
( *'-' | *'Bytes' )
continue

;;
esac

# echoでは駄目 dashで「\」がエスケープ扱いされるため
printf '%s\n' "${LINE}"
#echo "${LINE}" # 【debug】

done

) }


fileSizeDelSh(){ (

while read -r LINE ; do

# 行末のファイルサイズ部分を削除
# 行末から半角空白が最初に出現するまでを消去する
LINE="${LINE% *}"

# 行末の連続空白を削除する
LINE="${LINE%${LINE##*[! ]}}"

# 行末の連続空白を削除する_whileとcase
#while true ; do
#LINE="${LINE% }"
#case "${LINE}" in
#( *' ' )
#continue
#;;
#( * )
#break
#;;
#esac
#done


printf '%s\n' "${LINE}"
done

) }


filePathXsumSh(){ (
# ファイルパス     checkSum
# ↓
# checkSum *ファイルパス


while read -r LINE ; do

# 「ファイルパス+半角空白連続-1個」部分を抽出
filePath="${LINE% *}"

# 「半角空白1個+チェックサム」部分を抽出
checkSum="${LINE#${filePath}}"
# 先頭半角空白を削除
checkSum="${checkSum# }"


# ファイルパス末尾の連続半角空白を削除
filePath="${filePath%"${filePath##*[! ]}"}"


#printf '%s\n' "${LINE}"                   # 【debug】
#printf '\033[7m%s\033[0m\n' "${filePath}" # 【debug】
#printf '\033[7m%s\033[0m\n' "${checkSum}" # 【debug】


# 「 *」を挟んで出力
printf '%s *%s\n' "${checkSum}" "${filePath}"


done
) }


# iconvから処理を開始すること

if stdinTemp="`iconv -f cp932 -t utf8`"
then true
else exit 1
fi


printf '%s\n' "${stdinTemp}" | tr '\\' '/' | headerFooterCrDelSh | fileSizeDelSh | filePathXsumSh

外部コマンドは文字コード変換用のiconvと、Windowsディレクトリ区切りの「\」をLinuxの「/」へ変換するtrです。他はシェルの基本機能で済ませてます。
シェルの変数展開を多用してるのが特徴です。

意外とめんどくさい題材

cutやawkで切り貼りすれば簡単にできるかな、と思ってたんですが、あんまりコマンドとは相性がよくなくて、cut等で組んだ試作品は不格好になりました。

  • Windowsのファイルパスでも半角空白文字は普通に使われる。「半角空白は使わないでね」というわけにもいかない。
  • cutコマンドでは「左から1番目」「左の2番目から3番目」という指定はできるが、「最後の1番目」が難しい。ファイルパスに半角空白が入ると、cutコマンドではフィールド番号がずれてしまう。
  • revコマンドで左右をひっくり返してからcut、という手もあるが、これは日本語を含んだ文字列をrevコマンドでちゃんと使えることが前提になる。やってみたらできてはいたけれど……。

変数展開はとても使える

CR="`printf '\015'`"

while read -r LINE ; do

# 行末のCRを削除
LINE="${LINE%${CR}}"

たとえば最短一致で削除するときに、文字列を直接に書き込むだけでなく、シェル変数を入れてもいいそうです。
この例では、行末のCRを削除するのに、シェル変数に入れたCRを使ってます。
bash拡張機能というわけでもなく、dashでも使えます。