†DOSとバッチとスクリプト†
作成開始日 2018.09.27
最終更新日 2018.09.27
dir ??????????.htm
for %%f in (??????????.htm)
などとすれば良い筈だが、実際にはこれでは期待した結果は得られない。
●問題点1:指定文字数以下のファイルがすべて含まれてしまう
例えば、5文字のファイル名を持つBATファイルを抽出するために「dir ?????.bat」とすると、5文字以下のすべてのファイルが含まれてしまう。「test1.bat」のような5文字ファイル名だけではなく、「test.bat」や「vz.bat」や「c.bat」なども全て該当してしまう。仕様なのかも知れないが、使う側から見ればバグとしか考えられない。では、上記のように10文字指定すると、10文字以下のファイル名がすべて抽出されるのかと言うと−−実は更に酷い状況になる。
●問題点2:「?」は7個までしか意味をなさない
つまり、上記のように「?」を10個並べると、個数が無視されて「*」と同じなってしまう。10文字以下どころか、11文字でも20文字でも50文字でも全て該当してしまう。恐らく、これは8.3時代の名残で、最長ファイル名が8文字である以上、「?」を8個(以上)並べたものは「*」と同等に扱われるのだろう。
●問題点3:日本語ファイル名は「?」5個で全該当
上記は半角英数字のファイル名の場合だが、日本語ファイル名に関しては「?」5個で「*」に該当してしまう。これもDOS時代の名残のなのか、それともUTF-8で新たに発生した問題だか不明だが、日本語ファイル名が混じっている状態では、「?」は4個までしか使えない。
●対処方法
まあ、これらは長年放置されてきたバグで、一ユーザーにはどうしようもない。DOSでは「?」は使わない、というのが最善の自衛策。とは言え、じゃあ、どうすんの?というハナシになるのだが−−例えば、バッチに文字列の長さを取得する関数があれば良いのだが、そんな便利なものがあるはずもなく、各ユーザーさんが文字数カウントのルーチンを自作している状況。もう、バッチは止そうぜ、perlにしよう!かとも思ったが、まあ、今回は次のような方法で対処。
setlocal enabledelayedexpansion for %%f in (*.htm) do ( set st0=%%f set st1=!st0:~0,10!.htm if "!st0!"=="!st1!" (echo %%f) )基本的な考え方は、頭から10文字切り取って、元のファイル名と同じならば長さは10文字、という単純なもの。10文字以上のファイル名ならば当然同じにはならないし、10文字未満の場合も「頭から10文字」の中に拡張子部分が食い込んでくるので、同一にならない(例:test1234.htm→test1234.h.htm)。ただし、拡張子がないファイルを抽出する場合は、指定文字数未満でも一致してしまうので要注意(ダミーの拡張子を付けるという対処法はあるが)。