試される大地から

furaiboが送る技術ブログ。プログラミングのTipsなど書いていきます。

ファイル全体の行数を表示するPerlスクリプト


最近Perlを覚えようと思い、ちょっとPerlスクリプトを書いてみた。前回の記事で書いたシェルスクリプトをすべてPerlで置き換えた。かなり長くなってしまったが、なんとか完成することが出来た。


#!/usr/bin/perl

# プラグマ
use strict;


# サブルーチン定義
# ファイル一覧を取得
sub get_files_list {

	# 変数
	my @files_array = {};				# ファイルの一覧を示すリスト
	my @tmp_array   = {};				# 一時的なリスト
	my $dir   = $_[0];				# ディレクトリパス(1つめの引数)
	my $depth = 0;					# 階層の深さ
	if (defined($_[1])) {
		$depth = $_[1];				# 階層の深さ(2つめの引数)
	}

	# 処理
	opendir my $dh, $dir or die "$dir:$!";
	while (my $file = readdir $dh) {
		next if $file =~ /^\.{1,2}$/;		# ディレクトリ一覧の'.'や'..'をスキップする
		if (-d $file) {
			if ($depth == 0) {
				@tmp_array = get_files_list($dir.$file, $depth+1);		# 再帰呼び出し
				push @files_array, @tmp_array;					# 配列に要素の追加
			} else {
				@tmp_array = get_files_list($dir."/".$file, $depth+1);		# 再帰呼び出し
				push @files_array, @tmp_array;					# 配列に要素の追加
			}
		} else {
			my $file_path = $dir;						# ファイル名
			if ($depth > 0) { $file_path = "${file_path}/"; }
			$file_path ="${file_path}${file}\n";
			#print $file_path;
			push (@files_array, $file_path);					# 配列にファイル名を追加
		}
	}
	closedir $dh;

	# 配列内の不要な要素を除去
	for (my $i = 0; $i <= $#files_array; $i++) {
		if ($files_array[$i] =~ "HASH\([0-9a-z]*\)") {
			splice @files_array, $i, 1
		}
	}

	# 戻り値
	return @files_array
}


# 総行数をカウントする
sub count_sum_of_lines{

	# 変数
	my $sum = 0;			# 総行数
	my $filename = $_[0];		# ファイル名(1つめの引数)

	# 処理
	open(FILE, $filename) or die "Can't open `$filename': $!";
	while (sysread FILE, my $buffer, 4096) {
		$sum += ($buffer =~ tr/\n//);
	}
	close FILE;

	# 戻り値
	return $sum;
}


# 各拡張子ごとの行数をカウントする
sub count_num_lines{

	# 変数
	my ($files_array, $ext_array) = @_; 	# リファレンスを受け取る
	my %lines_array = ();			# 空の連想配列

	# 連想配列の初期化
	for (my $i = 0; $i <= $#$ext_array; $i++) {
		$lines_array{$$ext_array[$i]} = 0;
	}

	# 連想配列の要素に各拡張子ごとの行数を格納する
	for (my $i = 0; $i <= $#$files_array; $i++) {
		while (my($key, $value) = each(%lines_array)) {
			if ($$files_array[$i] =~ ".+\.$key") {	
				$lines_array{$key} += count_sum_of_lines($$files_array[$i]);
			}
		}
	}

	# 戻り値
	return %lines_array;	
}


# 行数を集計し、出力する
sub print_num_lines {

	# 変数
	my %lines_array = @_;		# 連想配列(1つめの引数)
	my $sum = 0;			# 指定ファイルの総行数

	# 出力
	print "<内訳>\n";
	while (my($key, $value) = each(%lines_array)) {
		print $key." : ".$lines_array{$key}."\n";
		$sum += $lines_array{$key};		# 総行数をカウントする
	}
	print "\n総行数 : ${sum}\n";			# 総行数を出力

}


# 変数定義
my $path = './';				# 対象ディレクトリ名(相対パス・絶対パス両方OK)
my @ext  = ("py", "js", "html");		# 行数をカウントするファイルの拡張子(ピリオド抜き)

# 処理
my @files = &get_files_list($path);		# ファイルの一覧を配列として取得
my %lines = &count_num_lines(\@files, \@ext);	# 行数をカウントする(リファレンスを引数として渡す)

# 行数を表示・集計
&print_num_lines(%lines)


Perlは時代遅れの言語だと思ってまじめにやっていなかったのだけども、RubyPythonといったLLの先祖のような存在だと知り、少しやってみたら割と奥が深くておもしろいと思った。しかし、同時に読みやすく描くのはなかなか技術が要りそうだと思った。


そしてRubyPythonPHPといった言語と似たところがあってこうした後発の言語がPerlの言語構造を上手く取り入れて書きやすくなるように工夫しているのだなと感じさせられた。


Perlは簡単ではないが、UNIXで動かすことができ、MacやLinuxにデフォルトでインストールされ、高い互換性があるので、移植性を最大限重視する場合には悪くない選択だと思うようになった。




今は初めてのPerlを読みつつ勉強中。オライリージャパンからは電子版も買えるので、タブレットにデータを移してで簡単に読むことができます。Perlに興味のある方は購入検討の価値ありだと思います。


初めてのPerl(第6版)

初めてのPerl

初めてのPerl