PowerCMS™

【東京セミナー】6月6日(木) 企業Webリニューアル。最初に押えたい要件定義の進め方と、最新CMSで出来ること

PowerCMS ブログ

ホーム > PowerCMS ブログ > Perl のワンライナーについて

2016年07月19日

Perl のワンライナーについて

Movable Type や PowerCMS は、主に Perl というプログラミング言語で開発されています。

Perl を習得することで各種プラグインの実装などができるようになりますが、GNU/Linux, Unix 環境で各種タスクをこなす際にも有用なプログラミング言語ですので、実例にも触れながら perl コマンドを使ったワンライナーの有用性について Tips を書きます。

製品サポートなどの様々な調査において個人的にも欠かせないツールとなっています。

申し送り事項

掲載されているサンプルは自己責任において、実行前に対象をバックアップするなどして慎重に実行ください。当記事に掲載されたコードを実行することによる問題については、いかなる場合においても一切の責任は負いかねます。

perl コマンド

Perl プログラムは、 perl コマンドを使って実行することができます。

Perl プログラムは、ファイルに記述して実行することが多いと思いますが、プログラムを perl コマンドの引数に直接指定することも可能で、1行のコマンドで様々な処理を実現できます。これをワンライナーと呼んだりします。

perl コマンドの使い方

perl コマンドの使い方は下記のコマンドで確認できます。

$ perl -h

また、perldoc コマンドを使用して、下記のコマンドを実行すると、より詳細なオンラインドキュメントを閲覧できます。

$ perldoc perlrun

perldoc コマンドは、Perl の各種モジュールに記述された POD (Plain Old Document) と呼ばれるドキュメントを、ページャを通して表示することができるコマンドで、開発時にとても有用です。

mt:Entry* タグのドキュメントを参照する

$ perldoc $MT_HOME/lib/MT/Template/Tags/Entry.pm

上記のようにパスを指定して対象のモジュールのドキュメントを参照することができたり、

CGI モジュールのドキュメントを参照する

$ perldoc CGI

上記のようにインストール済みのモジュール名を指定して対象のモジュールのドキュメントを参照することができたりします。

perl コマンドで良く使うコマンドライン引数(スイッチ)

下記のコマンドライン引数は頻繁に使用するため、覚えておくと有用です。perl コマンドではスイッチと呼びます。

-e スイッチ

-e スイッチは、eval の略で、指定した Perl プログラム文字列を実行することができます。最もよく使うスイッチです。

$ perl -e 'print "Hello, World\n"'

-I スイッチ

-I スイッチは、Include の略で、指定したディレクトリのパスを Perl のライブラリパスとして設定できます。

$ perl -I/path/to/lib -I/path/to/lib2

-M スイッチ

-M スイッチは Module の略で、指定した Perl モジュールをロードします。(use Foo; 相当)

$ perl -MFoo -e '...'

これを使って、よく特定の Perl モジュールがインストール済かを検査したり、特定の Perl モジュールのバージョン情報の確認などをします。

$ perl -MArchive::Zip -e1

上記でエラーがでなければインストール済と判定できます。

$ perl -MArchive::Zip -e 'print "$Archive::Zip::VERSION\n"'

上記で Archive::Zip モジュールのバージョンが確認できます。

= とつなげることで特定の関数をインポートすることもできます。(use Foo qw(bar); 相当)

$ perl -MFoo=bar -e '...'

-l スイッチまたは -E スイッチ

前述の例では print 分の最後に改行コードを追加し、改行ありで出力していますが、実際には出力内容に改行が欲しいことがほとんどなので、-l スイッチや -E スイッチを使用すると便利です。

-l スイッチは、line の略で、print 文の最後に、改行コードを追加するような挙動になります。

$ perl -le 'print "Hello, World"'

また、Perl 5.10 以降は、say 関数が追加され、print 文でいちいち改行コードを追記する必要がなくなりました。

say 関数のような Perl 5.10 以降の新しい機能を使用する場合は -e スイッチの代わりに、-E スイッチを使用します。

$ perl -E 'say "Hello, World"'

Perl 5.10 未満をお使いの場合は -E スイッチが存在しないため注意が必要です。

以上が後述のスイッチを除き、頻繁に使うスイッチになると思います。上記以外には、日本語を取り扱う上で有用な -C スイッチなどがあります。

perl コマンドとパイプの組み合わせ

perl コマンドはパイプと組み合わせて使用するとさらに有用です。

その際に組み合わせて使用するスイッチも紹介します。

-n スイッチ

-n スイッチが何の略称かはわかりません。パイプで渡ってくる出力結果を while (<>) { ... } で実行するような挙動になります。

例えば、find コマンドのように .cgi が拡張子であるファイル一覧を出力するようなケースなどでは下記のように記述します。

$ ls -1 $MT_HOME | perl -nle 'm|\.cgi$| and print'

perldoc perlrun のサンプルでは、カレントディレクトリにある直近1週間以内に更新したファイルを削除するサンプルが掲載されています。

$ find . -mtime +7 -print | perl -nle unlink

perl コマンドを awk コマンドや sed コマンド代わりに使う

awk コマンドや sed コマンドはそれぞれ有用ですが、perl コマンドで代用することも可能です。

awk コマンドの代わりに使う

awk コマンドの代わりとして perl コマンドを使用する場合は、-F スイッチと -a スイッチを覚えると有用です。

例えば、awk コマンドの help に記載のあった、/etc/passwd からユーザー名だけを取り出すサンプルは下記になります。

$ awk -F: '{ print $1 }' /etc/passwd

これを perl コマンドに置き換えると下記になります。

$ perl -F: -anle 'print $F[0]' /etc/passwd

-F スイッチは Field speparator の略で、-a スイッチは auto split の略です。

上記の例では、-F スイッチでセパレータ(今回はコロン)を指定し、-a オプションでセパレータで区切られたフィールドを @F 配列にセットする挙動になるため、awk のサンプルと同一の結果になります。

頑張れば CSV ファイルの処理などもできるように思うかもしれませんが、そう単純でもないので、そういう場合は csvkit などの専用ツールを使った方が良いです。

餅は餅屋です。

sed コマンドの代わりに使う

sed コマンドの代わりとして perl コマンドを使用する場合は、-p スイッチを覚えると有用です。(多分 print の略)

-p スイッチを指定すると、パイプで渡ってくる出力結果を while (<>) { ...; print "$_\n"; } で実行するような挙動になります。-n スイッチとの併用はできません。

sed コマンドでよくあるファイルの内容を置換して出力するサンプルが下記です。

$ sed -e 's/MT/PowerCMS/g' file.txt

これを perl コマンドに置き換えると下記になります。

$ perl -pe 's/MT/PowerCMS/g' file.txt

-p を指定することで print + 改行コードの出力部分を省略できるので、sed による置換のようになります。

また、GNU sed のように標準出力をリダイレクトすることなく、ファイル内置換を実施するための -i スイッチ(多分 in place の略)が perl コマンドにも存在しており、sed 的なワンライナーに組み合わせると便利です。

上記の例を下記のように実行すると、file.txt のバックアップが file.txt.orig として生成されたような動きになり、file.txt 内の MT という文字列は、すべて PowerCMS という文字列に置換されます。

$ perl -pi.orig -e 's/MT/PowerCMS/g' file.txt

正規表現は Perl の仕様になるので、sedgrep などでスイッチの違いによる正規表現の細かい仕様差異を知らなくて済むという利点があります。

Movable Type および PowerCMS での応用

以上を踏まえて、Movable Type および、PowerCMS の調査などに役立てるためのいくつかの Tips を紹介します。

カレントディレクトリを $MT_HOME においた方が何かと都合が良いので、$MT_HOMEmt-config.cgi の設置されたアプリケーションディレクトリ)にカレントディレクトリがある前提で説明します。

これ以降の手順は実運用環境では絶対に試さないよう強くお願いいたします。

mt-config.cgi からデータベース関連の情報を取得する

まずは簡単なファイルの読み込みと、テキスト処理から。

$ perl -nle '/^\s*D(?:B|atabase)/i and print' mt-config.cgi

MT のバージョンを取得する

ファイルから直接ではなく、MT のモジュールの機能を使って MT 関連の情報を取り出す場合は、-I スイッチで、$MT_HOME/lib$MT_HOME/extlib にパスを通した上で、-M スイッチで MT モジュールを読み込むのが常套句です。

また、MT の各種情報を取り出すためには、MT のインスタンスが必要なので、instance メソッドで初期化します。

まずは簡単なサンプルで、MT のバージョンを取得してみます。

$ perl -Ilib -Iextlib -MMT -le 'print MT->instance->version_id'

なお、bash のような高機能なシェルを使っている場合は、ブレース展開が使用できるため、-I スイッチは下記にまとめられます。

$ perl -I{,ext}lib -MMT -le 'print MT->instance->version_id'

記事タイトルを一覧出力する

MT オブジェクトを操作するオペレーションを個人的には良く使います。下記はブログ ID が 3 のブログから、id の昇順で記事を10件取り出してタイトルを出力しています。日本語がタイトルに含まれる場合は先ほど少し触れた -C スイッチを組み合わせると便利です。

$ perl -I{,ext}lib -MMT -CO -le 'print $_->title for MT->instance->model("entry")->load({ blog_id => 3 }, { limit => 10, sort => "id", direction => "asc" })'

メールを送る

MT::Mail モジュールを使ってメールを送るなんてこともできます。

$ perl -I{,ext}lib -MMT::Mail -e 'MT::Mail->send({ To => "me@example.com", Subject => "テスト"}, "テストです\n") or die MT::Mail->errstr'

特定の記事を1万件コピーする

記事を1万件コピーして、パフォーマンスのテストをしたいような時にワンライナーで記事を投入したりできます。例えば記事 ID が 10 の記事を1万件コピーするワンライナーが下記です。(セミコロンで文を区切っているのでワンライナーとは言えないですが…)

$ perl -I{,ext}lib -MMT -e '$orig = MT->instance->model("entry")->load(10); do { $e = $orig->clone; $e->id(undef); $e->basename("post_$_"); $e->save or die $e->errstr } for 1..10000'

番外編

MT のライブラリに限らず、さらに視野を広げると様々な処理が Perl ワンライナーで実現できます。

カレントディレクトリを閲覧する簡易 HTTP サーバを立てる

MT や PowerCMS でも利用している PSGI のアプリケーションサーバを使って、簡易 HTTP サーバを立てて、コンテンツの確認などができます。

$ perl -S plackup -MPlack::App::Directory -e 'Plack::App::Directory->new(root => ".")'

この例は perl コマンドの例というよりは、plackup の例になりますが、plackup コマンドのコマンドラインスイッチは perl コマンド互換になっています。

アルファサードのリポジトリのリンク一覧を Markdown 形式で取得する

Mojolicious という Perl の Web フレームワークに同梱されている様々な機能は、ojo というワンライナー用のモジュールにて簡易に利用することが可能なので、スクレイピングなどが簡単にできます。

$ perl -Mojo -E 'say g("https://github.com/alfasado?tab=repositories")->dom->find(".repo-list-name > a")->map(sub { sprintf "- [%s](https://github.com%s)", $_->text, $_->attr("href") })->join("\n")'

アルファサードのリポジトリのリンク一覧を Markdown 形式で取得する(GitHub API 版)

上記のスクレイピングは最終手段で、API が用意されている場合は、API を使った方が楽で便利です。

API を使うにしても Perl のワンライナーが有用です。

これも Mojolicious のようなオールインワンな Perl モジュールを使うと楽にできますが、敢えて、Perl の標準モジュールおよび、標準的なモジュールで実施するなら下記のようになります。(2ページ以降は省略)

$ perl -MLWP::UserAgent -MJSON -e 'printf "- [%s](%s)\n", $_->{name}, $_->{html_url} for @{JSON->new->decode(LWP::UserAgent->new->get("https://api.github.com/users/alfasado/repos")->decoded_content)}'

まとめ

perl コマンドを習得することで様々な処理がワンライナーで実行できることを確認いただけたかと思います。

紹介したものはいずれも比較的シンプルで用途も限定されたものですが、組み合わせや工夫次第で、様々なタスクに取り入れることができます。

製品サポートではこれらの技術を駆使して様々な調査や作業の省力化を図っています!

Perl を使って様々な困難や問題に立ち向かって問題解決したい方、デキる方、またはそのような人が周りにいる方がいらっしゃいましたら、人材は随時募集しておりますので、ぜひともお声がけください。


カテゴリー
技術情報

Recent Entries