研究室の技術職員から「あるドライブの特定拡張子のファイルリストをつくるバッチファイルを作成してくれない?」と要請があったので,久しぶりにさくっとバッチファイル (Batch File) を書いた.
バッチファイルのいろいろなエッセンスがそこそこつまったもの(?)ができたので,備忘録的にここに残しておく.
Microsoft Windows 10 Home (64bit)
ドライブを選択し,for
で全ファイルを探索し,指定拡張子のファイルパスを出力する.
またファイル数をカウントする.
@echo off rem 2018-01-15 rem 溶けかけてるうさぎ MeltingRabbit rem 選択ドライブから,特定拡張子のファイルリストを生成. rem また,ファイル数をカウントする. rem . rem Ver 1.0 初版 rem Ver 1.1 表示を修正 rem Ver 1.2 パスに & があるとコケるのを修正 title DocList set HOME_DIR=%~d0%~p0 call :GET_TIMESTAMP set OUTPUT_DIR=%HOME_DIR%%TIMESTAMP% echo 指定ドライブから特定拡張子(txt/doc/docx/xls/xlsx/ppt/pptx/pdf)のファイルリスト作成します. echo. :SELECT_DIR set /p INPUT="ドライブを選択してください >>" echo. if not "%INPUT:~1%"=="" ( echo アルファベット1文字で入力してください. echo. goto SELECT_DIR ) if not exist "%INPUT%:\" ( echo %INPUT%ドライブは存在しません. echo. goto SELECT_DIR ) echo 選択ドライブ:%INPUT% echo 出力フォルダ:%OUTPUT_DIR% echo 処理を開始するには何かキーを押してください . . . pause >nul echo. echo 処理中... set /a COUNT_TXT=0 set /a COUNT_DOC=0 set /a COUNT_DOCX=0 set /a COUNT_XLS=0 set /a COUNT_XLSX=0 set /a COUNT_PPT=0 set /a COUNT_PPTX=0 set /a COUNT_PDF=0 mkdir %OUTPUT_DIR% cd /d %INPUT%:\ rem ドライブ情報出力 dir >> %OUTPUT_DIR%\dir.txt rem 再帰処理 for /r %%F in (*.*) do ( rem echo %%F rem echo %%~xF set FILE_PATH=%%F if /i "%%~xF"==".txt" (call :COUNT_AND_OUTPUT txt COUNT_TXT ) if /i "%%~xF"==".doc" (call :COUNT_AND_OUTPUT doc COUNT_DOC ) if /i "%%~xF"==".docx" (call :COUNT_AND_OUTPUT docx COUNT_DOCX) if /i "%%~xF"==".xls" (call :COUNT_AND_OUTPUT xls COUNT_XLS ) if /i "%%~xF"==".xlsx" (call :COUNT_AND_OUTPUT xlsx COUNT_XLSX) if /i "%%~xF"==".ppt" (call :COUNT_AND_OUTPUT ppt COUNT_PPT ) if /i "%%~xF"==".pptx" (call :COUNT_AND_OUTPUT pptx COUNT_PPTX) if /i "%%~xF"==".pdf" (call :COUNT_AND_OUTPUT pdf COUNT_PDF ) ) echo txt : %COUNT_TXT% 個 >> %OUTPUT_DIR%\count.txt echo doc : %COUNT_DOC% 個 >> %OUTPUT_DIR%\count.txt echo docx : %COUNT_DOCX% 個 >> %OUTPUT_DIR%\count.txt echo xls : %COUNT_XLS% 個 >> %OUTPUT_DIR%\count.txt echo xlsx : %COUNT_XLSX% 個 >> %OUTPUT_DIR%\count.txt echo ppt : %COUNT_PPT% 個 >> %OUTPUT_DIR%\count.txt echo pptx : %COUNT_PPTX% 個 >> %OUTPUT_DIR%\count.txt echo pdf : %COUNT_PDF% 個 >> %OUTPUT_DIR%\count.txt echo. echo 処理が終了しました. echo. echo txt : %COUNT_TXT% 個 echo doc : %COUNT_DOC% 個 echo docx : %COUNT_DOCX% 個 echo xls : %COUNT_XLS% 個 echo xlsx : %COUNT_XLSX% 個 echo ppt : %COUNT_PPT% 個 echo pptx : %COUNT_PPTX% 個 echo pdf : %COUNT_PDF% 個 echo. echo 終了するには何かキーを押してください . . . pause >nul exit :GET_TIMESTAMP rem 時刻文字列を生成し, rem TIMESTAMPへ格納する. set DAT=%DATE% set TIM=%TIME% set YER=%DAT:~0,4% set MON=%DAT:~5,2% set DAY=%DAT:~8,2% rem 時間に空白が入る時がある set EXP=%TIM:~0,1% if "%EXP%"==" " ( set HOU=0%TIM:~1,1% ) else ( set HOU=%TIM:~0,2% ) set MIN=%TIM:~3,2% set SEC=%TIM:~6,2% set TIMESTAMP=%YER%.%MON%.%DAY%_%HOU%.%MIN%.%SEC% exit /b :COUNT_AND_OUTPUT rem 細々とした処理. rem 第1,2引数を使用. set TYPE=%1 set COUNT_TYPE=%2 rem いわゆる遅延展開による2重変数展開 call set /a %COUNT_TYPE%=%%COUNT_TYPE%% + 1 echo "%FILE_PATH%" >> %OUTPUT_DIR%\%TYPE%.txt exit /b
バッチパラメタ%0
はバッチファイル自身をさす.
%~d0%~p0
では,ドライブ名とパスを展開して,バッチファイルがあるディレクトリをHOME_DIR
に代入している.
set HOME_DIR=%~d0%~p0
call
でサブルーチンを呼び出している.
exit
だと終了してしまうので,exit /b
とする.
後者では引数を2つ渡しており,これはバッチパラメタ%1, %2
で取得可能.
なお,バッチファイルでは全ての変数はグローバルスコープである.
call :GET_TIMESTAMP
if /i "%%~xF"==".txt" (call :COUNT_AND_OUTPUT txt COUNT_TXT )
set /p INPUT="ドライブを選択してください >>"
if not "%INPUT:~1%"=="" (
set YER=%DAT:~0,4% set MON=%DAT:~5,2% set DAY=%DAT:~8,2%
if not exist "%INPUT%:\" (
>nul
で標準出力をnullに捨てることによって,pause
コマンドの結果を表示させない.
pause >nul
for /r
で再帰処理.
(*.*)
とワイルドカードでセットしているので,拡張子のあるファイルのみ処理させる.
%%~xF
はファイル拡張子を取得する修飾子.
rem 再帰処理 for /r %%F in (*.*) do ( rem echo %%F rem echo %%~xF set FILE_PATH=%%F if /i "%%~xF"==".txt" (call :COUNT_AND_OUTPUT txt COUNT_TXT ) if /i "%%~xF"==".doc" (call :COUNT_AND_OUTPUT doc COUNT_DOC ) if /i "%%~xF"==".docx" (call :COUNT_AND_OUTPUT docx COUNT_DOCX) if /i "%%~xF"==".xls" (call :COUNT_AND_OUTPUT xls COUNT_XLS ) if /i "%%~xF"==".xlsx" (call :COUNT_AND_OUTPUT xlsx COUNT_XLSX) if /i "%%~xF"==".ppt" (call :COUNT_AND_OUTPUT ppt COUNT_PPT ) if /i "%%~xF"==".pptx" (call :COUNT_AND_OUTPUT pptx COUNT_PPTX) if /i "%%~xF"==".pdf" (call :COUNT_AND_OUTPUT pdf COUNT_PDF ) )
set DAT=%DATE% set TIM=%TIME%
%TIME%
で現在時刻が取得できるわけだが,10時以前だと,_1
のようにスペースが入ってしまう.
つまり0埋めされていない.
タイムスタンプなどで使う場合,固定長がよいので0埋めする.
rem 時間に空白が入る時がある set EXP=%TIM:~0,1% if "%EXP%"==" " ( set HOU=0%TIM:~1,1% ) else ( set HOU=%TIM:~0,2% ) set MIN=%TIM:~3,2% set SEC=%TIM:~6,2%
call
による多重変数展開高校生の時に発見した手法.
call
を使うと多重変数展開ができる.
rem いわゆる遅延展開による2重変数展開 call set /a %COUNT_TYPE%=%%COUNT_TYPE%% + 1
136行目は,たとえばCOUNT_TYPE
の値がCOUNT_TXT
の場合,
call set /a %COUNT_TYPE%=%%COUNT_TYPE%% + 1 ↓ set /a COUNT_TXT=%COUNT_TYPE% + 1
と展開される.
&
が含まれるとエラーになるecho "%FILE_PATH%" >> %OUTPUT_DIR%\%TYPE%.txt
を,
echo %FILE_PATH% >> %OUTPUT_DIR%\%TYPE%.txt
としてしまうと,パスに&
が含まれるとエラーになる.
例えばC:\hoge\fu&ga.txt
というファイルがあった場合
echo %FILE_PATH% >> %OUTPUT_DIR%\%TYPE%.txt ↓ echo C:\hoge\fu&ga.txt >> ${output_file_path}.txt
と展開され,&
がコマンド区切りと認識されてしまう.
もちろんga
というコマンドは存在しないのでエラーになる.
パスを""
でかこえばこのエラーは出なくなるが,出力ファイルリストも""
でかこわれてしまうので,どうしたものか,といったところ.
2018年1月21日 追記
回避策を見つけた.
詳細を次の記事でまとめた.
名前
Email (※公開されることはありません)
コメント