- Perl ›
- デバッガ
Perlデバッガの手引き
Perlのとても便利な道具のひとつにデバッガがあります。デバッガを使うとスクリプトを一行づつたどって変数の中身を見たり、ブレークポイントを設定してその位置で停止したりすることができます。
デバッガは本当に便利なのですがPerlをやっていても意外と知らない人がいます。ひとたびデバッガを覚えてしまうと試験をするときに手放せなくります。Perlを覚えたての時期からどんどん使っていって欲しいツールです。そんなデバッガのコマンドとテクニックをまとめてみました。
デバッグ用のスクリプト
デバッグ用の簡単なスクリプトを準備しました。debug.plという名前で保存してください。このスクリプトを使用してデバッガの解説をします。
my $message = 'Hello'; my @nums = (1, 2, 3); my %scores = (math => 80, english => 77); my $twice = twice(5); # ブレークポイント $DB::single = 1; for my $num (@nums) { # 条件付ブレークポイント if ($num == 2) { $DB::single = 1 } print "$num\n"; } sub twice { my $num = shift; return $num * 2; }
デバッガの起動
デバッガを起動するには「-d」オプションを指定してperlを起動します。
perl -d debug.pl
デバッガを起動すると最初の行で停止します。
main::(a.pl:4): my $message = 'Hello';
デバッガを終了するには「q」を使用します。
q
ヘルプを見るには「h」を使用します。
h
では順番にデバッガのコマンドを覚えていきましょう。
1. 実行系のコマンド
Perlデバッガの実行系のコマンドを解説します。
n - 一行実行
スクリプトを一行実行するには「n」を使用します。「n」と入力して「Enter」を入力すると次の行に進みます。
最初の状態で「n」を実行すると次のように表示され一行進んでいることが確認できます。
main::(a.pl:5): my @nums = (1, 2, 3);
「n」「Enter」「n」「Enter」と入力していくとスクリプトの最後にたどり着いてスクリプトが終了します。
Debugged program terminated. Use q to quit or R to restart,
デバッグをやめるかリスタートするかを聞かれますが2回目のデバッグを行いたいときは必ずqでデバッグをいったん終えてください。
「n」「Enter」「n」「Enter」と入力するのは少し面倒です。実は「n」「Enter」「Enter」「Enter」で行を進めていくことができます。「n」か「s」が直前に入力されていた場合は「Enter」で直前のコマンドを繰り返すことができます。
nは「next」のnだと覚えると覚えやすいです。
s - シングルステップ実行
スクリプトをシングルステップ実行するには「s」を使用します。「n」との違いはサブルーチンの内部の処理もたどってくれることです。
「n」で一行実行を勧めてスクリプトをサブルーチンの呼び出しがある行まで進めてください。
main::(a.pl:8): my $twice = twice(5);
この行で「s」を実行するとサブルーチンの内側の処理に移動することができます。
main::twice(a.pl:21): my $num = shift;
c - ブレークポイントあるいは指定した行まで実行
「c」はブレークポイントあるいは指定した行まで実行するコマンドです。cはcontinueの頭文字のcです。
c 5
を実行すると5行目の直前までが実行されます。
main::(a.pl:5): my @nums = (1, 2, 3);
次に引数を与えずに
c
を実行すると文中のブレークポイントの次の位置まで進みます。
main::(a.pl:13): for my $num (@nums) {
# ブレークポイント $DB::single = 1;
はスクリプトの中に埋め込むことができるブレークポイントです。変数の内容などを見たい場合にその直前の行あたりにブレークポイントを設定しておくと、そこで実行を停止することができるのでとても便利です。
2. 表示系のコマンド
表示系のコマンドを解説します。
p - 変数の内容を表示
「p」で変数の内容を表示することができます。たとえば$messageという変数を表示したい場合は以下のようにします。
p $message
x - 変数の内容を展開して表示
「p」はスカラ変数の内容を表示するには便利ですがハッシュや配列、またもっと複雑なデータ構造を表示するには適していません。
「x」を使用するとデータの内部構造をわかりやすく表示することができます。「x」の引数にはリファレンスを渡す必要がありますので注意してください。
たとえば%scoresの内容を表示するには次のようにします。\はリファレンスを取得するためのものです。
x \%scores
次のように変数のデータがわかりやすく表示されます。
0 HASH(0x19b205c) 'english' => 77 'math' => 80
3. その他のよく使用するコマンド
その他のよく使用するコマンドを解説します。
v - 周辺の行の表示
「v」で周辺の行を表示することができます。
v
4行目で「v」を実行すると次のように周辺の行が表示されます。
1: use strict; 2: use warnings; 3 4==> my $message = 'Hello'; 5: my @nums = (1, 2, 3); 6: my %scores = (math => 80, english => 77);
「v」を何回も実行すると下の行に表示を移していくことができます。
. - 現在行の表示
「v」を何回も実行すると下の行に表示が移動してしまいます。そういうときに現在行に戻るために「.」を使用することができます。
.
任意のperlの文
デバッガでは任意のPerlの文を実行することができます。以下は変数が定義されているかどうかを確認してみるためにdefined関数を使った例です。
print defined $message;
どのような文でも実行することができるので確認に役立ちます。
4. デバッグのテクニック
よく使用するデバッグのテクニックを紹介します。
文中ブレークポイント
Perlではスクリプトの中にブレークポイントを埋め込むことができます。DBクラス(デバッガのためのクラス)のsingleという変数に1を代入しておくとその位置でシングルステップ実行に処理が切り替わる仕組みです。
$DB::single = 1;
これは本当に便利なのでどんどん使ってください。また試験を終えた後はスクリプトの中から削除するのを忘れないようにしましょう。
条件つきブレークポイント
デバッグを行っているとある条件のときだけ処理をそこで止めて変数の内容を見たいというときがあります。そのような場合は、条件文と「$DB::single = 1」を組み合わせて使います。今回のサンプルでは$numが2のときにその位置でデバッガが停止するようにしています。
if ($num == 2) { $DB::single = 1 }
警告が発生した位置を調べる
スクリプトの試験をしていると以下のような未定義値を使用していますという意味の警告がよく発生します。
Use of uninitialized value
特に原因を発見するのが大変なのはfor文やwhile文などのループの中で警告が発生した場合です。これはどこかで代入すべきだったのに代入できていないとうことなので、その場所を特定する必要があります。
ほとんどの人はこのような場合はなんとなくこの場所だろうという位置までデバッガを進めると思うのですが、実は警告をキャッチする方法があります。
Perlでは警告をシグナルとして受け取ることができるので、ループのブロックの中に次のようなブレークポイントを仕掛けてあげればよいです。
# 警告をキャッチしてブレークポイントしかける $SIG{__WARN__} = sub { $DB::single = 1; };
デバッガで上下キーがきかずにヒストリー機能を使えない
Perlのデバッガで上下キーがきかずにヒストリー機能を使えない場合というのがあるかと思います。これは、Term::ReadLine::Gnuがインストールされていないことが原因です。
Term::ReadLine::Gnuをインストールするためには、以下のC言語のライブラリが必要です。
CentOS,RedHatの場合
yum -y install readline-devel
Term::ReadLine::Gnuのインストール
cpanmかcpanでTerm::ReadLine::Gnuをインストールします。
# cpanm cpanm Term::ReadLine::Gnu
# cpan cpan Term::ReadLine::Gnu
任意の位置でブレークポイントを指定してデバッガを止める
Perlのデバッガは便利です。デバッガを使うようになると、ぴたっと見たい位置で止めたいという気持ちがわいてくるかと思います。ぴたっと見たい位置で止めるにはどうすればよいでしょうか。
たとえば試験を書いているときに、同じ処理の同じ部分を何回も通過するということはよくあることです。こういう場合は「$DB::single = 1」というブレークポイントの記述だけではうまく止まることができませんね。以下の場合だと、最初のtotalが実行された時点で、ブレークポイントに引っかかってしまいます。
total(1, 2); # この処理のときだけ見たい total(3, 4); sub total { my ($num1, $num2) = @_; $DB::single = 1; my $total = $num1 + $num2; return $total; }
こういうときは条件付ブレークポイントを使います。
total(1, 2); # この処理のときだけ見たい $ENV{a} = 1; total(3, 4); sub total { my ($num1, $num2) = @_; $DB::single = 1 if $ENV{a}; my $total = $num1 + $num2; return $total; }
環境変数というのは、グローバル変数なので、ちょっと利用させてもらいます。環境変数aをして、設定されているときだけ、ブレークポイントを設定すると記述すると、ぴたっと止まりたい位置で止まることができます。これは、結構便利なテクニックなので、覚えておきましょう。
デバッガを積極的に活用してみてください
これでデバッガのコマンドとテクニックの解説を終わります。デバッガのコマンドはたくさんありますが、ここに書いておいてものだけ覚えておけばデバッグで困ることはないでしょう。デバッガは本当に有用なツールなので積極的に活用してみてください。