0. はじめに
ある日,チームリーダーから過去のプロジェクトの開発規模を知りたいので,ソースコードのステップ数を調べてくれという依頼が来た。問題はその依頼を受けた同僚で,なんとファイルを一つずつテキストエディタで開いて行数を数えようとしたので慌てて止めさせた。せめてファイルが全部でいくつあるのか数えてからやろうね。
で「30分待ってくれ」とお願いして急いで作ったのが今回のバッチファイルである。
1. 仕様案(お品書き)
ステップ数をカウントするフリーソフトなんて,その辺に転がっていそうな気がするが,情シス部門を通すヒマがないので自作する。
- 誰でも作れる(使える)ようにコマンドプロンプトから起動するバッチファイルとする。
- 複数のファイル名を指定でき,ワイルドカードも使うことが出来る。
- サブディレクトリ以下を再帰的に検索することができる。
- 単純な行数をカウントするものとする。空行やコメント行もカウントする。
- 最後にステップ数の合計を表示する。
2. 基本技術
行数のカウント方法
テキストファイルの行数をカウントするためには find
コマンドを使う方法が知られている。詳しくは参考文献を参照されたい。
問題は最終行が改行のみの場合,一行だけ少なくカウントされてしまうことや,出力形式が無意味に複雑(謎のハイフンとファイル名と行数)なので,この出力をパースするのが少し面倒である。パイプで find
コマンドに引き渡してやれば両者の問題を解決できる。
c:\qiita>find /c /v "" sample.txt
---------- SAMPLE.TXT: 100
c:\qiita>find /c /v "" < sample.txt
100
c:\qiita>type sample.txt | find /c /v ""
101
ちなみに sapmle.txt
は下記のような内容である。最後の101行目は改行のみとなっている。
サブディレクトリ以下を再帰的に検索する方法
for /R
コマンドを使う方法もあるが,dir
コマンドの出力を使ったほうが速いことが知られている。詳しくは筆者の別記事を参照のこと。
for /F "usebackq tokens=*" %%I in ( `dir /s /b /a-d 検索パターン 2^>NUL` ) do (
for /F "usebackq" %%J in ( `type "%%~I" ^| find /c /v ""` ) do set LINE=%%J
echo %%~I !LINE!
)
3. 実装コード
実装コードを以下に示す。なお,ファイルのサイズ(バイト単位)も出力し,最後に合計も出力するようにした。
@echo off
rem ----------------------------------------------------------------------------
rem テキストファイルの行数をカウントします
rem ----------------------------------------------------------------------------
setlocal enabledelayedexpansion
set ROPT=0
rem ------------------------------------------------------------------------
rem オプション解析
rem ------------------------------------------------------------------------
set ARGS=
if "%~1"=="" goto USAGE
:LOOP
set OPT=%~1
if /I "%OPT%"=="/R" set ROPT=1&&goto ENDIF
if "%OPT:~0,1%"=="/" goto ERROR
if defined ARGS (
set ARGS=%ARGS% "%~1"
) else (
set ARGS="%~1"
)
:ENDIF
shift
if "%~1"=="" goto BREAK
goto LOOP
:ERROR
echo オプション %OPT% には対応していません!
exit /b
:BREAK
if not defined ARGS (
echo ファイル名を指定して下さい!
exit /b
)
rem ------------------------------------------------------------------------
rem ステップ数/ファイルサイズのカウント
rem ------------------------------------------------------------------------
set DIROPT=/b /a-d
if "%ROPT%"=="1" (
set DIROPT=/s %DIROPT%
)
set ALL_LINE=0
set ALL_SIZE=0
echo ファイル名 行数 サイズ
for /F "usebackq tokens=*" %%I in ( `dir %DIROPT% %ARGS% 2^>NUL` ) do (
set SIZE=%%~zI
for /F "usebackq" %%J in ( `type "%%~I" ^| find /c /v ""` ) do set LINE=%%J
echo %%~I !LINE! !SIZE!
set /a ALL_LINE=ALL_LINE+LINE
set /a ALL_SIZE=ALL_SIZE+SIZE
)
echo 合計 %ALL_LINE% %ALL_SIZE%
exit /b
:USAGE
rem ----------------------------------------------------------------------------
rem ヘルプメッセージ
rem ----------------------------------------------------------------------------
echo テキストファイルの行数をカウントします。
echo.
echo iSTEP(.CMD) [/R] [ドライブ:][パス][ファイル名] ...
echo.
echo /R ファイルを再帰的に検索します。
exit /b
4. 実行例
引数なしで実行するとヘルプメッセージを表示する。
c:\qiita>istep
テキストファイルの行数をカウントします。
iSTEP(.CMD) [/R] [ドライブ:][パス][ファイル名] ...
/R ファイルを再帰的に検索します。
ファイル名の指定にはワイルドカードが使える。ファイル名と行数,サイズ間の区切り文字はタブである。
c:\qiita>istep *.cmd
ファイル名 行数 サイズ
HCASE.CMD 141 4169
HCASE2.CMD 157 4597
LCASE.CMD 82 2500
LCASE2.CMD 94 2817
UCASE.CMD 82 2506
UCASE2.CMD 94 2817
UCASE3.CMD 126 3654
ZCASE.CMD 165 4832
ZCASE2.CMD 180 5254
合計 1121 33146
5. おまけ
サンプルとして業務用のソースコードを掲載する訳にはいかないので,誰でも知っている題材として百人一首を例題にした。99首目の後鳥羽院とは後鳥羽上皇のことで「鎌倉殿の13人」での尾上松也氏の好演が思い出される。悲壮感漂う内容からして隠岐の島への流罪後に歌ったものかと思いきや,承久の乱の前とは意外だった。
6. 参考文献
本記事で採用した行数カウント方法は参考文献[8]による。
- Windowsコマンドでファイル行数を数える - Qiita
- windowsでファイルの行数を取得する方法 - Qiita
- 行数カウントしてって頼まれてサボった話 - Qiita
- ファイルの行数をカウントして変数に入れるワンライナーbat - Qiita
- Windows標準機能(cmd)で、フォルダ内の各テキストファイル・CSVファイルの行数カウントする。 - Qiita
- wc コマンド for windows - Qiita
- PowerShellステップカウンタ - Qiita
- 【bat】Windowsのバッチファイルネタ帳 - Qiita
- 後鳥羽天皇 - wikipedia
- ちょっと差がつく『百人一首講座』- 小倉山荘
- 一日一首 - 全日本かるた協会