ソースファイルの行数をカウントする(その2)

id:eel3:20080601 でソースファイルの行数をカウントする方法を書いたが、それらは特定のディレクトリ上に全ソースファイルがある場合にのみ有効な方法だった。

ところで、ソースが複数ディレクトリに分かれている場合などに、カレントディレクトリ以下の全ソースファイルの行数を調べるにはどうしたらよいだろうか?

Cygwin/MSYSのbash上の場合

Windows XPコマンドプロンプト」ではないが、MSYSやCygwinのシェル(多分bash)とUnix由来のfind*1を使えれるのならば話は簡単だ。

知っている人にとっては単純な話だが、findでカレントディレクトリ以下にある全ソースファイル名をピックアップし、それをwcの引数にすればよい。

$ wc -l `find . -name \*.[ch]`
   158 ./fs/bitmap.c
    86 ./fs/block_dev.c
  #------ 長いので中略 ------
   264 ./mm/memory.c
    68 ./tools/build.c
  8413 合計

catを使う場合も同じような感じだ。

$ cat `find . -name \*.[ch]` | wc -l
8413

ところでfindにはピックアップした個々のファイルに対して何らかの処理をさせる為のオプション-execがあるので、次のようにも書ける。但し処理速度は遅いようだ。全ファイルの合計行数を知りたい場合はgawk等で出力結果を加工する必要がある。

$ find . -name \*.[ch] -exec wc -l \{\} \; | gawk '{ n += $1 } END { print n }'
8413

コマンドプロンプトの場合

コマンドプロンプトでも、個々のファイルの行数を求めることは結構簡単にできる。しかし全ファイルの行数の合計を出すにはもう一工程必要なようだ。
取り敢えず「個々のファイルの行数を求めるだけ」で考えてみた。

Unix由来のfindを使う方法もあるが、

$ find . -name "\*.[ch]" -exec wc -l "{}" ";"
158 ./fs/bitmap.c
86 ./fs/block_dev.c
::-- 長いので中略 --
264 ./mm/memory.c
68 ./tools/build.c

この際、wc以外のUnix系ツールを使わないで何とかできないか?
ということでバッチファイルを書いてみた。

@echo off
:: lc.bat
:: カレントディレクトリ以下のCソース/ヘッダファイルの行数を求める。
:: findを使う方法だと出力形式がイマイチなので、wcを使う。

for /r %%i in (*.c *.h) do (
	wc -l "%%~i"
)
$ lc.bat
158 D:\archive\util\src\linux\fs\bitmap.c
86 D:\archive\util\src\linux\fs\block_dev.c
::------------ 長いので中略 ------------
264 D:\archive\util\src\linux\mm\memory.c
68 D:\archive\util\src\linux\tools\build.c

wcすら使わない(つまりWindows標準のコマンドのみの)方法もある。findを使うと表示形式が不細工なので、wcっぽく表示するように小細工してみた。実行速度は遅め。for文の逆引用符部分にリダイレクトを書いたらエラーになったので、別のバッチファイルに分割している。

@echo off
:: lctiny.bat
:: 指定された 1つのファイルの行数だけを返す

find /c /v "" <%1
@echo off
:: lc.bat
:: カレントディレクトリ以下のCソース/ヘッダファイルの行数を求める。

for /r %%i in (*.c *.h) do (
	for /f "usebackq" %%n in (`call lctiny.bat "%%~i"`) do (
		echo %%n %%i
	)
)
$ lc.bat
158 D:\archive\util\src\linux\fs\bitmap.c
86 D:\archive\util\src\linux\fs\block_dev.c
::------------ 長いので中略 ------------
264 D:\archive\util\src\linux\mm\memory.c
68 D:\archive\util\src\linux\tools\build.c

但しこれらの方法では個々のファイルの行数しか分からない。行数の合計を知りたいなら、バッチファイルの出力結果を加工して合計を求めることになる。私ならgawkを使う。

$ lc.bat | gawk "{ n += $1 } END { print n }"
8413

*1:Windowsのfindコマンドじゃないので注意。