読者です 読者をやめる 読者になる 読者になる

週末には少しPerlを。

Perlスクリプトの学習日記です。

パターンにマッチした以降の行のみを出力するワンライナー

perl -ne '$f =1 if /pattern/; print if $f;' sample.txt

Zabbix::APIを使ってzabbixに登録されているホストを知る

統合監視ツールzabbixにはWebUI以外にJSON-RPCによるAPIが用意されておりまして、 このAPIを叩くためのcpanモジュールZabbix::APIを使う練習をしてみます。

Loginする

use Zabbix::API;

my $zbx = Zabbix::API->new(
    server => 'http://example.com/zabbix/api_jsonrpc.php',
    verbosity => 0,
    );

eval {
    $zbx->login(user => 'admin',password => 'MyPass')
};

if ($@) {
    die "Couldn't login : $@";
}

ホストのリストを取得する

fetchメソッドを使います。

my $hosts = $zbx->fetch('Host');

foreach my $h (@{$hosts}) {
    print Dumper ($h->data);
}

ホストグループを限定して取得するなら

my $hosts = $zbx->fetch('Host',
                     params => {
                         groupids => 8
                     }
);

foreach my $h (@{$hosts}) {
    print "Host name :".$h->data->{name};
    print "\n";
}

参考サイト

cpan https://metacpan.org/pod/Zabbix::API

Zabbix 公式 https://www.zabbix.com/documentation/2.2/manual/api

Date::Calcを使って今月の日数を知る

今月は何日間あるか、日数を知りたい。 そんな時にはDate::Calcに丁度よいモノが。

use Date::Calc qw(:all);

my ($year, $month, $day) = Today();
my $days = Days_in_Month($year, $month);

print "$year - $month - $day\n  $days days in this month.\n";

これで行けます。

IPv4アドレスのような何かにマッチする正規表現

量指定子(quantifier)の復習

0回以上の繰り返しは「*」、1回以上の繰り返しは「+」、n回以上m回以下の繰り返しは「{n,m}」と書きます。 1~3ケタの数字は「¥d{1,3}」と書くとよろしい。

IPv4アドレスのような何か

とりあえず以下のように書くとよろしい。

(\d{1,3}\.){3}\d{1,3}

数字1~3ケタとピリオド、これを3回繰り返して最後にもう一度数字。 あくまで「最大3ケタ」であって、255を超えるような実際にはIPv4アドレスでは有り得ない数字にもマッチしてしまいますが、 ログファイルの検索などで「とりあえずその場をしのぐ」にはこれで十分使えそうです。

元ネタ

Famous Perl One-Liners Explained, Part VII: Handy Regular Expressions

CGI::Application::Plugin::DBHを使ってデータベースのテーブル内容を表示してみる

データベースに接続する

前回に引き続きCGI::Applicationの練習をいたします。 データベースにアクセスするための機能がPlug-inにありまして、これを使います。 cgiapp_init の中でDBに接続するコードを書きます。

use base 'CGI::Application';
use CGI::Application::Plugin::Session;
use CGI::Application::Plugin::DBH (qw/dbh_config dbh/);

sub cgiapp_init {
    my $self = shift;

    my $dbname = "db";
    my $dsn = "DBI:Pg:dbname=$dbname";
    my $dbUser = "user";
    my $dbPass = "pass";

    $self->dbh_config($dsn, $dbUser, $dbPass);
}

HTML::Templateを使う

CGI::ApplicationはデフォルトでHTML::Templateを使えるようになっていまして、 これを使って表示させるとします。 setupの中でテンプレートファイルの所在を指定します。

sub setup {
    my $self = shift;
    $self->start_mode('listview_mode');

  # 略
    $self->tmpl_path('/some/path/to/template');
}

DBのテーブルを表示する

テーブルtblHogeの中身をlistview_modeというrun_modeで表示させるとします。

sub listview_mode {
    my $self = shift;
    my $template = $self->load_tmpl('listview.tmpl');

    my $sql = 'SELECT hoge_id, hoge_time, hoge_title from tblHoge LIMIT 5';
    my $sth = $self->dbh->prepare($sql);
    $sth->execute;

    my @rows;
    my ($hoge_id, $hoge_time, $hoge_title);
    $sth->bind_columns(\($hoge_id, $hoge_time, $hoge_title));

    while ($sth->fetch) {
        push @rows, {
            HOGE_ID => $hoge_id,
            HOGE_TIME => $hoge_time,
            HOGE_TITLE => $hoge_title,
        };
    }

    $template->param(LISTVIEW => \@rows);
    return $template->output;
}

テンプレートファイルlistview.tmplは以下のような感じ。

<html>
<head>
  <meta charset="utf-8">
  <title>Hoge</title>
</head>
<body>
  <table>
    <TMPL_LOOP NAME="LISTVIEW">
      <tr>
        <td><TMPL_VAR NAME="HOGE_ID"></td>
        <td><TMPL_VAR NAME="HOGE_TIME"></td>
        <td><TMPL_VAR NAME="HOGE_TITLE"></td>
      </tr>
    </TMPL_LOOP>
  </table>
</body>
</html>

昔は使えたかもしれない書き方

Web検索していると昔のブログ記事などで 「selectall_hashref(あるいはfetchrow_hashref)が返すリファレンスをそのままテンプレートに渡してOK!」 といったような記述に出会うことがありますが、少なくとも今はそんなことはできません。 DBIのメソッドの仕様が Ver.1.15 ~ 1.20の付近で変わった?とのこと。

参考:using CGI, DBI and HTML::Template

CGI::Applicationを練習するための最小に近いコードを書いてみる

CGI::Applicatioin

もっと他のフレームワークが今の流行なのかもしれませんが、 温故知新という言葉もあります。 CGI::Applicationを使って文字通りCGIアプリを作るお勉強をしようと思い立ったのです。

最小構成に近い形ということで、テキストボックスに文字列を入力すると 「hoge」を「fuga」に置換して表示するWebアプリ(?)を書いてみます。

.cgiファイル

本体はMyWebApp.pmというファイルに格納してWebサーバーのDocumentRootの外に置きます。 クライアントがアクセスする.cgiファイルは次の通り。

#!/usr/bin/perl

use strict;
use warnings;

use lib "/path/to/CGIApp";
use MyWebApp;

my $webapp = MyWebApp->new();

$webapp->run();

MyWebApp.pmファイル

冒頭部分(setup)

package MyWebApp;
use base 'CGI::Application';
use strict;
use warnings;

sub setup {
    my $self = shift;
    $self->start_mode('mode1');
    $self->run_modes(
        'mode1' => 'shform',
        'mode2' => 'shresult',
        );
}

入力フォームがmode1、結果表示画面がmode2です。

入力フォーム

sub shform {
    my $self = shift;
    my $q = $self->query();

    my $output = '';

    $output .= $q->start_html(-title => 'My Web App');
    $output .= $q->start_form();
    $output .= $q->textfield(-name => 'fruits');

    $output .= $q->hidden(-name => 'rm', -value => 'mode2');

    $output .= $q->submit();
    $output .= $q->end_form();
    $output .= $q->end_html();

    return $output;
}

hiddenでrmをmode2としてサーバーに渡します。

結果表示

sub shresult {
    my $self = shift;
    my $q = $self->query();

    my $fruits = $q->param('fruits');
    my $output = '';

    $output .= $q->start_html(-title => 'My Web App - Results');
    $fruits =~ s/hoge/fuga/;
    $output .= $fruits;
    $output .= $q->end_html();

    return $output;
}

1;

これだけです。 本当はもっと複雑なことをやらせたいものですが、 まずは練習ということでココまで。