Control live 00:00

Perlワンライナー入門

坂本 昭

自己紹介

坂本 昭 (さかもと あきら) / @sakamoto_akira_

  • 経歴
    • ブラック企業 (JAVA / 偽装請負)
    • 株式会社gumi (Python / ソーシャルゲーム)
    • 株式会社フリークアウト (Perl / 広告配信システム)

マジックザギャザリングがすごい好きです

トーク概要

  • perlワンライナー便利ですよという紹介
  • ハンズオンで少し使っていただく
  • ワンライナーがなんとかしてくれるのはどういう処理か

余った時間に

  • ワンライナーでやっつけた問題を適用例を時間の限り紹介

Perlワンライナー便利です

  • 1行なので手軽に書けるが、かなり色々な処理をさせれる
  • 1行書くぶんには学習曲線もなだらか。覚えやすい技術

Perlワンライナーを使う方が増えて人類の生産性が上がればいいと思っています

なんでPerlワンライナー便利なの

Perlの得意分野を使い倒している技術です

  • 得意分野
    • テキストデータ相手に
    • 書き捨てのスクリプトを書く

このたぐいの作業を3行以下のスクリプトでやっつけるなら無敵

なぜこの領域が得意なのか

  1. 正規表現の機能が強力
  2. 便利な特殊変数と構文が揃っていて簡潔に表現出来る
  3. 1行でもPerl, 膨大なCPANにアクセス可能

テキストデータ相手の作業は以外と多い

よくある業務: さかもとの場合

  • 外部の会社とのデータ連携でチェックなど
    • html, csv, xml
  • 調査対応でログを漁る
    • ltsv, json

まとめ1

  • テキストデータ相手に書き捨てるなら、Perlの得意分野です
  • 覚えやすくて強力なので、学習コスト的にはすぐに黒字化します
  • 便利なので使ってみましょう

便利なので使ってみましょう

  • ハンズオン用のリポジトリを用意してあります
  • 今回の発表資料から手元でコピペできるようにしてあります
$ git clone https://github.com/sakamossan/yapc_perl_oneliner_beginner.git
$ cd yapc_perl_oneliner_beginner

今回の発表資料: https://www.swipe.to/7299cm#page=Z0S6J59Zt

早速使ってみます

  • grep代わりに使ってみます
  • ios_app_names.tsvからzombieという単語を含む行を抽出します
$ perl -nlE "/zombie/ and print" ios_app_names.tsv

おなじないの説明

$ perl -nlE "/zombie/ and print" ios_app_names.tsv
  • -n 1行づつ処理するモードになります 読み込んだ1行は $_ に入ります
  • -l 行ごとに処理するに際して改行周りをよしなに処置してくれます
  • -E 引数をスクリプト扱いにします
  • /zombie/ $_ に入っている文字列を正規表現にあてる
  • and print パターンマッチの結果が真の場合に $_ をprintする

動作イメージ

# 入力から1行づつ読み込んで $_ に入れる (-nオプション)
while ($_ = <ARGV>) {
    # 改行文字をよしなに処理 (-lオプション)
    chomp $_;
    # 正規表現にマッチしたら出力
    print $_ if $_ =~ /zombie/;
}

いかがでしょうか

  • とりあえずgrep代わりに使ってみました
  • このままだとgrepの方が便利なのでもうちょっと違う例を紹介します

Perlのメタ文字や特殊変数を使ってみる

  • decks.jpは自分が管理しているマジックザギャザリングのサイトです
  • curlしたhtmlから、aタグのリファラ属性を抽出してみます
$ curl -s "http://decks.jp/" | \
  perl -nlE ' /<a .*href="(\S+)"/ and say $1'
$ curl -s "http://decks.jp/" | \
  perl -nlE ' /<a .*href="(\S+)"/ and say $1'
  • /<a .*href=“(\S+)“/ aタグのリファラ属性をキャプチャ
    • \S 空白以外にマッチするメタ文字 [^ \t\n\r\f]
  • $1 正規表現マッチにてキャプチャされた部分が格納される

動作イメージ

# パイプで渡されたhtmlを1行づつ読み込んで
while (defined($_ = <ARGV>)) {
    chomp $_;
    # aタグを引っ掛けて、リファラ属性だけキャプチャする
    if ($_ =~ /<a .*href="(\S+)"/) {
        # マッチした場合、キャプチャした部分を出力する
        say $1;
    }
}

次にモジュールをインポートしてみます

  • urlエンコードされている部分がわかりません
  • デコードしてくれる関数をもってきて使ってみます
$ curl -s "http://decks.jp/" | \
  perl -Ilib -MURI::Encode=uri_decode \
    -nlE ' /<a .*href="(\S+)"/ and say uri_decode($1)'

次にモジュールをインポートしてみます

$ curl -s "http://decks.jp/" | \
  perl -Ilib -MURI::Encode=uri_decode \
    -nlE ' /<a .*href="(\S+)"/ and say uri_decode($1)'
  • -I lib 大文字 -Iオプション lib以下のモジュールをuse可能に
  • -MURI::Encode=uri_decode -Mでモジュールのuse, uri_decode関数をuse

動作イメージ

use lib "lib";  # libディレクトリ以下をuseできるように
use URI::Encode "uri_decode"; # 目的の関数をuse

while (defined($_ = <ARGV>)) {
    chomp $_;
    if (/<a .*href="(\S+)"/) {  # マッチしたら
        say uri_decode($1);     # デコードして出力
    }
}

いかがでしょうか2

Perlワンライナーの仕事のフレーム

  1. テキストデータの中から
  2. 正規表現で文字列を抽出して
  3. 抽出したデータを関数、クラスに渡す

上記の条件に当てはまれば、Perlワンライナーが得意なことだと思います

Perlワンライナーの仕事のフレーム

たとえば

  1. sitemap.xml (テキストファイル) から
  2. URL(文字列)を抽出して
  3. ステータスコードが200以外のものを出力する(LWPに渡す)

以上です

  • この機会に是非使ってみてください
  • ミニマルPerlという本に今日の内容の詳しいところが書いてあります

minimal perl

ここからはおまけです

```

  • 僭越ながら業務上の問題をワンライナーでやっつけた例を幾つか
  • なんか鮮やかなのがありましたら #yapcasiaD にいただきたいと思います

流れが速いログが見にくい

  • tail -F しようにも流れが速すぎてどんな感じだか読みにくい
  • 出力行を絞って見やすくしたい

rand()

$ tail -F fast.log | perl -nlE 'rand() < 0.5 and say'
  • rand()が0~1の数値をランダムで返す
  • 上記の例だとランダムで半分間引いた状態になります

どれくらいの割合でbotが来てるか確かめたい

  • googleのボットが来たときにしか発現しない不具合がありそう
  • まずざっくりgoogleのボットってどれくらい来てるのか割合が知りたい

HTTP::BrowserDetect

$ cat access.log | perl -Ilib -MHTTP::BrowserDetect \
  -nlE '/" "(.+?)"$/ and say HTTP::BrowserDetect->new($1)->robot' \
  | sort | uniq -c
  • 集計はsort | uniq -c まかせが便利です

scriptタグの中身が見たい

  • 埋めてもらったscriptタグがどんな感じで埋まってるか見たい
  • ついでにどんなjsが埋まっているかもみたい
  • <script> … </script> の中身

/<script/ .. /<\/script>/

$ curl -s "http://decks.jp/deck/1" \
  | perl -nlE '/<script/ .. /<\/script>/ and say'
  • フリップフロップ演算子 (正規表現を「..でつなぐ」)
    • 1個目にマッチしてから2個目にマッチするまで出力
  • Exceptionのログとかを見るのにも便利でした

似ている言葉だけ抽出したい

  • だいたい諦めるけど、機械の力で諦めないで済む場合がある
  • たとえば「マグニート」に似てる名前のアーティスト探したい

-MString::Trigram=compare

$ perl -MString::Trigram=compare \
  -nlE 'say compare("magneto", $_), "\t", $_ ' musicians.txt \
  | sort -n | tail -3

0.1 Marvin Gaye
0.111111111111111   Incognito <- 無事にインコグニートが!
0.117647058823529   Maroon 5  

LTSV形式から特定のキーだけとってきたい

これにてネタ切れです

$ cat ltsv | tr "\t" "\n" | perl -nlE "/^path:/ and say $'"
  • パースの仕方無数にある
  • 可読性があって土壇場で思い出しやすい

ありがとうございました