MENU

溶けかけてるうさぎ HP BLOG TOP RECENT ARTICLES POPULAR ARTICLES ABOUT THIS BLOG

CATEGORY

大学 (85) 航空宇宙 (55) 写真 (25) 旅行 (14) 飯・酒 (11) コンピュータ (88) その他 (13)

TAG

ARCHIVE

2018 (92) 2017 (80) 2016 (0)

RECENT

【駅メモ】4年目に突入して,ようやく3000駅突破 【WebRTC】Raspberry Pi搭載ロボットをWebRTCで遠隔操作しようとして失敗した 【航空宇宙】航空宇宙アドベントカレンダー 始まります! 【Perl】YAPC::Tokyo 2019 のチケットを確保しました! 【カメラ】Canonから富士フイルムに乗り換えました

【bat】バッチファイルで特定拡張子のファイルリスト作成

2018-01-17

研究室の技術職員から「あるドライブの特定拡張子のファイルリストをつくるバッチファイルを作成してくれない?」と要請があったので,久しぶりにさくっとバッチファイル (Batch File) を書いた.

バッチファイルのいろいろなエッセンスがそこそこつまったもの(?)ができたので,備忘録的にここに残しておく.

1.動作環境

Microsoft Windows 10 Home (64bit)

2.仕様

ドライブを選択し,forで全ファイルを探索し,指定拡張子のファイルパスを出力する.

またファイル数をカウントする.

3.ソースコード

@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

4.Tips

バッチファイルの存在ディレクトリを取得

バッチパラメタ%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%:\" (

一時停止と標準出力をnullに捨てる

>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%

バッチファイルで取得できる時間は0埋めされないのでその処理

%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日 追記

回避策を見つけた.

詳細を次の記事でまとめた.

5.関連記事

コメントを投稿

名前

Email (※公開されることはありません)

コメント