I ♥ WordPress

[時間割:Perl]『ミニマルPerl』その15
2009/01/16 01:00 posted by kunkichi

木曜日は「Perl」です。今回からfindコマンドです。これまでやってきた grep、sed、awk については、Perlで置き換えれるように見てきたのだけど、find の場合は「Perl との組み合わせ」でいろいろやっていきます。

ミニマルPerl Unix/LinuxユーザのためのPerl習得法
Tim Maher
オライリージャパン
売り上げランキング: 96883
  • ファイルのテスト機能。シェルやtestコマンドで使うようなやつです。
    例:sample.txt が通常のファイルだったら。 -f sample.txt and print;例:sample.binが通常のファイルじゃなかったら。! -f sample.bin and print;ファイル名を省略して$_にすることもできます。
    例:$_ が 通常のファイルだったら。-f and print $_;例:$_が通常のファイルじゃなかったら。! -f and print $_;
  • これ以外にもテスト機能の指定はできます。findじゃできないような、テキストとバイナリのテスト、実行ユーザの権限に準じたアクセス権でのテスト、などなど。
  • find と Perl を組み合わせでは、find で一連のパスを作っておいて、フィルタをかけるのにPerlを使います。$ find . -type -name '*.dat' |
    > find /var/log -mtime -3
    これにPerlでフィルタをかけます。> | perl -wnl -e '/-f and -T/ and print;'上記の例では、findでカレントディレクトリ配下の”*.dat”というファイル名で、かつ、最終更新日が3日以内のファイル名をリストアップして、最後にPerlで、通常ファイル、かつ、テキストファイルのものだけを抽出しています。
  • 名前のマッチングとかはPerlの強力な正規表現をつかったほうがらくちんです。$ find . -type -f | perl -wnl -e '/.+¥.dat$/ and print;'ちなみにfindの場合は以下。$ find . -type f -name "*.dat"ファイル名のマッチングが一つだけしかないなら、それほどでもないけど、以下のように複数のファイル名のマッチとかの場合は、括弧で囲んだ上、エスケープして、複数のファイル名の条件は、-oでつなぐ、そして、ファイル名のマッチにはワイルドカードレベルのものしか使えない、となり結構面倒。$ find . -type f \( -name '*.dat' -o -name '1¥.*' -o '*34*' \)
  • フルパスでファイルのリストがあって、この中から、特定の「ファイル名だけ」でマッチをしたい場合、以下のように-aオプションでパスを分解して使うと良い。$ find . -type f | perl -wnla'/' -e '$F[-1] =~ /abc$|*cde*|^123/ and print;'
  • 逆に特定の「ディレクトリ配下」という指定もできる。$ find . -type f | perl -wnl -e '-T and m:data/\w+\.dat:i and print;'-Tでテキストファイル限定、mを使って正規表現中にパスを表すスラッシュをいちいちエスケープしないように、iで大文字小文字無視。こういうのはfindだけではちょっと難しいのでかなり便利。

とりあえず今日はここまで。

[時間割:Perl]『ミニマルPerl』その14
2009/01/12 23:53 posted by kunkichi

祝日ですががんばります。月曜日は「Perl」。AWKをPerlでやってみようの最後です。演算子とか組み込み関数とか。

ミニマルPerl Unix/LinuxユーザのためのPerl習得法
Tim Maher
オライリージャパン
売り上げランキング: 96883
  • AWKもプログラミング言語なので演算子が存在する。
  • 関係演算子(==とか!=とか)でAWKは文字列と数値を区別しないのに対し、Perlは数値と文字列で演算子の記述が異なる(数値だと==なのが、文字列だとeq とか。)
  • 算術演算子はどちらも同じ。
  • AWKもプログラミング言語なので標準で組み込まれている関数が存在する。
  • 似たような関数はあるけど、引数が違うとか、意味が違うとか、記述が違うとか、結構異なる点もあることに注意。
  • 関数を使ってワンライナーを作ってみる。$ perl -wnl -e 'print substr $_, 0, 40; sample.txtこれだけでもAWKとは流儀が異なる点がある。
    • substrの第2引数は開始位置のオフセットをあ表すけど、AWKの場合、最初の1文字目は1になるのに対して、Perlは0になる。
    • Perlだと、関数の引数を囲む()は省略できる。
  • exprをAWKで実装した例が紹介されている。#!/bin/sh
    awk "BEGIN{ print $*; exit }"
    • $*で引数を展開するのはシェルの役割と思ってよいのかな?
    • AWKでは、入力ループは暗黙なので、単一処理はその外側で文を書く。そのためにBEGINを使っている
    • ループに入らずに処理を終えるためにexit。

    などなど、いろいろ面倒(っぽいw)。Perlで書くとらくちん。#!/bin/sh
    perl -wl -e 'print $*;'

    • $*をシェルが展開するのは同じ。
    • -wlだとループしない。
    • 処理が終われば勝手に終了するのでexitする必要はない。
  • メインの話とは関係ないけど、Lingua::EN::Inflectで単語を自動的に複数形にできる。これ、細かいところで便利かも。Damian先生作!#!/usr/bin/perl -w
    # stop.pl
     
    use Lingua::EN::Inflect 'PL_N';
    use strict;
    use warnings;
     
    for( my $i=1; $i<10; $i++ ){
      printf("%d %s\n", $i, PL_N 'apple', $i );
    }
    $ ./stop.pl
    1 apple
    2 apples
    3 apples
    4 apples
    5 apples
    6 apples
    7 apples
    8 apples
    9 apples
  • 範囲演算子を使用する場合、指定された範囲の最後の要素では’E0′を返す。これを使うと、ブロック間にスペースを入れるように出力するとかできる。
    前回例であげたHTMLファイルから<div>〜<div>で囲まれた範囲を表示するワンライナーでやってみる。$ perl -wnl -e '$status=/^<div>$/ ... /^<\/div>$/ and print;if($status =~ /E0$/){ print "";}' sample.html
    <div>
    ここが最初のブロック
    </div>
     
    <div>
    ここが2番目のブロック
    </div>
     

これでAWKのところも終わりました。次はfindコマンドの機能をPerlでやっていきます。

[時間割:Perl]『ミニマルPerl』その13
2009/01/09 01:44 posted by kunkichi

木曜日は「Perl」です。引き続きAWK編。今回は「パターン範囲」で特定のレコード「群」を抜き出すのをやってみたいと思います。

ミニマルPerl Unix/LinuxユーザのためのPerl習得法
Tim Maher
オライリージャパン
売り上げランキング: 96883
  • AWKでは二つのパターンマッチをカンマで区切って指定すると、最初のパターンにマッチした行から二つ目のパターンにマッチした行までを抜き出すことができる。
    例えばapacheのログから特定の時間帯(例では2008/11/25の1:49:55から1:51:30まで)を抜き出す場合$ awk '/25\/Nov\/2008:01:49:55/ , /25\/Nov\/2008:01:51:30/' access_log.1
    127.0.0.1 - - [25/Nov/2008:01:49:55 +0900] "GET / HTTP/1.0" 200 〜
    127.0.0.1 - - [25/Nov/2008:01:49:56 +0900] "GET / HTTP/1.0" 200 〜
    127.0.0.1 - - [25/Nov/2008:01:49:57 +0900] "GET / HTTP/1.0" 200 〜
    ・・・
    127.0.0.1 - - [25/Nov/2008:01:51:28 +0900] "GET / HTTP/1.0" 200 〜
    127.0.0.1 - - [25/Nov/2008:01:51:29 +0900] "GET / HTTP/1.0" 200 〜
    127.0.0.1 - - [25/Nov/2008:01:51:30 +0900] "GET / HTTP/1.0" 200 〜
    Perlの場合は、カンマではなく、範囲演算子 .. で区切る。$ perl -wnl -e '/25\/Nov\/2008:01:49:55/ .. /25\/Nov\/2008:01:51:30/ and print;' access_log.1
  • 範囲演算子には … もある。この場合は2回目のパターンマッチは1回目のパターンマッチが「終わった後」である必要がある。といってもわかりにくいので、例を書いてみる。
    以下のようなテキストデータがあるとする。# cat sample.txt
    Make a Bath on Tuesday
    Take a Bath on Wednesday
    チュラチュラチュラチュラチュラチュララ〜ってやつですねw
    でこれを “Make 〜” で始まって “〜day” で終わるように範囲指定したいとする。
    • ドット2個の場合$ perl -wnl -e '/^Make/ .. /day$/ and print;' sample.txt
      Make a Bath on Tuesday
    • ドット3個の場合$ perl -wnl -e '/^Make/ ... /day$/ and print;' sample.txt
      Make a Bath on Tuesday
      Take a Bath on Wednesday

    つまりドット2個の場合は1回目のパターンと2回目のパターンが同じ行にある場合はそこで終わるけど、ドット3個の場合は1番目のパターンにマッチした「後」の行にマッチするというわけ。ログの調査とかだとドット3個の方が活用するシチュエーションが多い気がする。

  • これにさらにandでパターンマッチを追加する。例えば最初にログの日付でマッチする例をちょっと変えてみて、1:49から1:51のログを抜き出すとする。# perl -wnl -e '/25\/Nov\/2008:01:49/ ... /25\/Nov\/2008:01:51/ and print;' access_log.1
    127.0.0.1 - - [25/Nov/2008:01:49:00 +0900] "GET / HTTP/1.0" 200 〜
    127.0.0.1 - - [25/Nov/2008:01:49:01 +0900] "GET / HTTP/1.0" 200 〜
    127.0.0.1 - - [25/Nov/2008:01:49:02 +0900] "GET / HTTP/1.0" 200 〜
    ・・・
    127.0.0.1 - - [25/Nov/2008:01:50:58 +0900] "GET / HTTP/1.0" 200 〜
    127.0.0.1 - - [25/Nov/2008:01:50:59 +0900] "GET / HTTP/1.0" 200 〜
    127.0.0.1 - - [25/Nov/2008:01:51:00 +0900] "GET / HTTP/1.0" 200 〜
    最後の行を見るとわかると思うけど、このログはほぼ毎秒1回出力されているのに、最後の1:51は0秒のところしか出力されていない。本当はこのあとも1:51:59までこのログが出ている可能性がある。
    ということでちょっと変えてみる。少し先、1:52まで出力してみる。# perl -wnl -e '/25\/Nov\/2008:01:49/ ... /25\/Nov\/2008:01:52/ and print;' access_log.1
    ・・・
    127.0.0.1 - - [25/Nov/2008:01:51:58 +0900] "GET / HTTP/1.0" 200 〜
    127.0.0.1 - - [25/Nov/2008:01:51:59 +0900] "GET / HTTP/1.0" 200 〜
    127.0.0.1 - - [25/Nov/2008:01:52:00 +0900] "GET / HTTP/1.0" 200 〜
    うん、やっぱり続いている。
    ということでこれにもう一つパターンマッチを加えてみる。1:52を含まないパターンマッチを追加する。# perl -wnl -e '/25\/Nov\/2008:01:49/ ... /25\/Nov\/2008:01:52/ and !/25\/Nov\/2008:01:52/ and print;' access_log.1
    ・・・
    127.0.0.1 - - [25/Nov/2008:01:51:57 +0900] "GET / HTTP/1.0" 200 〜
    127.0.0.1 - - [25/Nov/2008:01:51:58 +0900] "GET / HTTP/1.0" 200 〜
    127.0.0.1 - - [25/Nov/2008:01:51:59 +0900] "GET / HTTP/1.0" 200 〜
    これでOK。こういう工夫は多少必要だけどわかってしまえばそれほどでもない。
  • 複数の範囲をマッチさせることもできる。たとえば以下のHTMLから<div>〜</div>で囲まれた範囲を抜き出す。$ cat sample.html
    <html>
    <head><title>複数範囲のマッチ</title></head>
    <body>
     
    <div>
    ここが最初のブロック
    </div>
     
    ここは表示されないはず
     
    <div>
    ここが2番目のブロック
    </div>
     
    </body>
    </html>
    $ perl -wnl -e '/^<div>$/ ... /^<\/div>$/ and print;' sample.html
    <div>
    ここが最初のブロック
    </div>
    <div>
    ここが2番目のブロック
    </div>

複数行を範囲で抽出するシチュエーションで本当に多いので、これはかなり使えるかも。

[時間割:Perl]『ミニマルPerl』その12
2009/01/06 02:44 posted by kunkichi

三日坊主にならないようにがんばりますw
月曜日は「Perl」です。引き続き、AWKの処理をPerlで実現していきます。今日はAWKの得意なパターンとアクションを組み合わせた処理です。

  • AWKの「パターン&アクション」の例$ awk -F":" '/^root/{ print NR ":" $1 }' /etc/passwd
    1:root
    AWKのいいところは、
    • アクションを指定していないパターンの場合は、レコードをそのまま自動的に出力する。$ awk -F":" '/^root/' /etc/passwd
      root:x:0:0:root:/root:/bin/bash
    • パターンを指定していない場合はアクションを全てのレコードに対してそのまま実行する。$ awk -F":" '{ print NR ":" $1 }' /etc/passwd
      1:root
      2:bin
      3:daemon
      4:adm
      5:lp
      ・・・
  • 上記のそれぞれをPerlで実装する。
    • パターンとアクション$ perl -wnlaF":" -e '/^root/ and print "$.:$F[0]";' /etc/passwd
      1:root
    • パターンのみ$ perl -wnlaF":" -e '/^root/ and print;' /etc/passwd
      root:x:0:0:root:/root:/bin/bash
      この場合は明示的にprintをつけないといけない。
    • アクションのみ$ perl -wnlaF":" -e 'print "$.:$F[0]";' /etc/passwd
      1:root
      2:bin
      3:daemon
      4:adm
      5:lp
      ・・・
  • AWKのBEGINとENDもそのままPerlで使える。apacheログのファイルサイズの合計と平均を出すサンプルスクリプト。サイズは10番目のフィールド($F[9])に出力されているものとする。# perl -wnla -e '
    > BEGIN{
    >   $total=0;
    >   $cnt=0;
    >   $average=0;
    > }
    > $total=$total+$F[9];
    > $cnt++;
    > END{
    >   $average=$total/$cnt;
    >   print "TOTAL:$total AVERAGE:$average";
    > }' access_log.1
    TOTAL:1100250219 AVERAGE:1559
    BEGINのブロックで変数を初期化しておいて(初期化していない場合は初期化されていないという警告が出る場合があるのと、最終的にデータがなかった場合にENDで出力する際に警告が出て、かつ、NULLになってしまうため。)、ENDでまとめて出力。
  • フィールド処理に対してマッチングするとより細かい条件を設定できる。/etc/passwdの中からUIDが一桁のものを抽出してUIDとユーザ名を出力する。# perl -wnlaF':' -e '($username, undef, $uid) = @F;$uid =~ /^\d$/ and print "$uid:$username";' /etc/passwd
    0:root
    1:bin
    2:daemon
    3:adm
    4:lp
    5:sync
    6:shutdown
    7:halt
    8:mail
    9:news
  • AWKのNF(最後のフィールド)は、Perlだと$F[-1]。
  • 段落モードの場合(-00)は、行単位でフィールド処理を行うのではなく、段落内の全ての文字列に対してフィールド処理が行われる。わかりにくいので以下の例で説明。
    例)sarコマンドでCPU使用率を定期的に取得した場合の出力結果は以下。# sar -P ALL -u 1 10
    1: Linux 2.6.X-X.X.X (www.example.com)   2009年01月06日
    2:
    3: 02時08分43秒       CPU     %user     %nice   %system   %iowait    %steal     %idle
    4: 02時08分44秒       all      0.00      0.00      0.00      0.00      0.00    100.00
    5: 02時08分44秒         0      0.00      0.00      0.00      0.00      0.00    100.00
    6: 02時08分44秒         1      0.00      0.00      0.00      0.00      0.00    100.00
    7:
    8: 02時08分44秒       CPU     %user     %nice   %system   %iowait    %steal     %idle
    9: 02時08分45秒       all      0.00      0.00      0.00      0.00      0.00    100.00
    10: 02時08分45秒         0      0.00      0.00      0.00      0.00      0.00    100.00
    11: 02時08分45秒         1      0.00      0.00      0.00      0.00      0.00    100.00
    12:
    ・・・
    47:
    48: 02時08分52秒       CPU     %user     %nice   %system   %iowait    %steal     %idle
    49: 02時08分53秒       all      0.00      0.00      0.00      0.00      0.00    100.00
    50: 02時08分53秒         0      0.00      0.00      0.00      0.00      0.00    100.00
    51: 02時08分53秒         1      0.00      0.00      0.00      0.00      0.00    100.00
    52:
    53: 平均値:        CPU     %user     %nice   %system   %iowait    %steal     %idle
    54: 平均値:        all      0.00      0.00      0.00      0.10      0.00     99.90
    55: 平均値:          0      0.00      0.00      0.00      0.30      0.00     99.70
    56: 平均値:          1      0.00      0.00      0.00      0.00      0.00    100.00
    ※わかりやすいように行番号を入れてますが実際には出力されていません。

    このうち、個々のCPU使用率のidle値の推移を取得する。
    $ perl -00 -wnla -e '/^¥d/ and print "$F[23] $F[-1]";'
    100.00 100.00
     
    100.00 100.00
     
    100.00 100.00
     
    100.00 100.00
     
    97.06 100.00
     
    100.00 100.00
     
    100.00 100.00
     
    100.00 100.00
     
    100.00 100.00
     
    100.00 100.00
     
    ポイントは以下。

    • 欲しいのは推移データだけなので、1行目のunameの出力と最後のサマリーの段落を出力しないように、段落の最初が数字(sarの個々の出力データは日付が最初に出力されている)の箇所にマッチした段落のみを抽出
    • さらに、個々の段落全体の文字列を最初から見ていくと、CPU0のidle値は24番目、CPU1のidle値は32番目なので、それぞれを@Fのインデックス指定で取得。インデックスは0オリジンなので、CPU0のidle値は$F[23]、CPU1のidle値は$F[31]、ただしCPU1のidle値はその段落全体で最後のフィールド最後になるので$F[-1]、として出力。

    といった感じで、表データの任意の値だけ取得というのもかんたんにできる。

まあ、こういうデータ抽出をするかどうかは別にして、自分なりの例を作ってやってみると理解しやすい気がしました。次回に続きます。

[時間割:Perl]『ミニマルPerl』その11
2009/01/02 03:11 posted by kunkichi

既に元旦も終わってますが、まあ元旦の分ということで(笑)。今年一発目の「Perl」の時間です。前回に引き続き、Perl で AWK を実現するところ。今回はAWKの最も得意なフィールド処理をPerlでやっていきます。

  • -naが前提とします。
  • 各フィールドは@Fに代入され、各フィールドへは配列のインデックスでアクセスできる。
  • 配列を変数に代入する場合、「途中」で不要なフィールドがある場合は、undefを使う。$ echo "aaa bbb ccc" | perl -wnla -e '($first,undef,$third)=@F;print "$first $third";'
    aaa ccc
    最初から途中までの場合は、単に指定しないだけでOK。
  • AWKとPerlで変数をprintで出力する場合、
    • AWKは変数をカンマ、もしくはスペースで並べる(AWKはダブルクォート内で変数展開とかされないので複数の引数を取りたい場合は必須)。スペースの場合は連結して出力、カンマの場合はOFSで指定されているセパレータを使って区切り出力される。
    • Perlはダブルクォート内で変数展開できるので、複数の変数もダブルクォートで囲んで単一の引数とすれば意識する必要なし。あえて複数の引数を指定する場合は必ずカンマで区切ること。この場合、セパレータはダブルクォート内に入れてしまうか、$,に定義する必要がある。$ echo "aaa bbb ccc" | perl -wnla -e '($first,undef,$third)=@F;print $first,$third;'
      aaaccc
      $ echo "aaa bbb ccc" | perl -wnla -e '($first,undef,$third)=@F;$,=" ";print $first,$third;'
      aaa ccc
  • 入力レコードを特定の文字列で分割する場合はAWKと同じく、-Fを使う。

ちょっと短めだけど、元旦の夜だし、まずは少しでも毎日やることを大事にしたいと思います。

[時間割:Perl]『ミニマルPerl』その10
2008/12/17 22:56 posted by kunkichi

どっひゃー!もう12月も半ばまで。サボりにサボりまくったな〜、、、とはいうものの一応本はどんどん読み進めてまして、いろいろと活用もしております、はい、、、さて、気を取り直してアウトプット再開です。

前回(ってかなり前だな、、、orz)sedのところまで進んでたので、今回からはAWKの機能をperlで実現していきます。

AWKよりもPerlが優れているところ

  • けちなマッチングが行える。
    例えばkunkichi:*:100:100:Test User1:/bin/bash:みたいな/etc/passwdのエントリの1カラム目だけが取りたい場合。普通に書くと、$ perl -wnl -e 's/^(.+):/$1/g and print $1;' /etc/passwd
    kunkichi:*:100:100:Test User1:/bin/bash
    となってうまく行かないパターンにハマりがち。もちろん以下のように正規表現で”:”を考慮するように見直せばオーケーだけど、、$ perl -wnl -e 's/^([^:]+):.*/$1/g and print $1;'
    kunkichi
    Perlだと、こんなことしなくても、ケチなマッチング(+の後の?がそれ)を使って「マッチする最短の単位」で拾える。$ perl -wnl -e 's/^(.+?):/$1/g and print $1;' /etc/passwd
    kunkichi
    うーん、awk でできないよ、っていうよい例が出ませんでした、笑
  • レコードセパレータのマッチング。改行とかもマッチングで拾えるということ。サンプルとして以下のようなテキストデータがあるとしてThis is a sample sentence and
    using Perl, you can match new
    line with regular expression.
    “new line”をマッチさせてみる。$ perl -00 -wnl -e '/new\nline/ and print;' sample.txt
    This is a sample sentence and
    using Perl, you can match new
    line with regular expression.
    ちなみに\sでもOK。$ perl -00 -wnl -e '/new\sline/ and print;' sample.txt

特殊変数いろいろ

  • 以下のサンプルデータを使います。# cat beatles.txt
    John Lennon
    Ringo Starr
    Paul McCartney
    George Harrison
    awkの場合、$ awk '{ print NR ":" $0 "(Nickname:" $1 ")"  }' beatles.txt
    1:John Lennon(Nickname:John)
    2:Ringo Starr(Nickname:Ringo)
    3:Paul McCartney(Nickname:Paul)
    4:George Harrison(Nickname:George)
    同じことをPerlでやると、$ perl -wnla -e 'print "$.:$_(Nickname:$F[0])"' beatles.txt
    1:John Lennon(Nickname:John)
    2:Ringo Starr(Nickname:Ringo)
    3:Paul McCartney(Nickname:Paul)
    4:George Harrison(Nickname:George)
  • セパレータ関連
    以下のサンプルデータを使います。$ cat 1_10.txt
    1 2 3 4 5 6 7 8 9 10
    セパレータを入力・出力で切り替えてみます。AWKの場合、awk 'BEGIN{RS=" ";ORS=",";}{ print $0 }' sample.txt
    1,2,3,4,5,6,7,8,9,10
    Perlの場合、perl -wnl -e 'BEGIN{$/=" ";$\=","}print;' sample.txt
    1,2,3,4,5,6,7,8,9,10
  • フィールドセパレータ。さっきのbeatles.txtをサンプルに使います。
    AWKの場合、awk 'BEGIN{FS=" ";OFS="|";}{ print $1, $2;}' beatles.txt John|Lennon
    Ringo|Starr
    Paul|McCartney
    George|Harrison
    Perlで。perl -wnlaF"\s" -e 'BEGIN{$,="\|";}print $F[0],$F[1];' beatles.txt
    John|Lennon
    Ringo|Starr
    Paul|McCartney
    George|Harrison
    Perlの場合は入力フィールドセパレータは変数がないので-Fを使う点に注意。
  • フィールド数
    AWKの場合、$ awk '{ print NF }' beatles.txt
    2
    2
    2
    2
    Perlの場合、$ perl -wnla -e '$num=@F;print $num;' beatles.txt
    2
    2
    2
    2
  • 引数の取得。
    AWKの場合、$ cat argv.awk
    BEGIN{
      print "ARGV=\"" ARGV[0],ARGV[1],ARGV[2] "\"";
      print ARGC;
    }
    $ awk -f argv.awk arg1 arg2
    ARGV="awk arg1 arg2"
    3
    AWKの場合は、自分自身も引数に含まれる。Perlの場合。$cat argv.pl
    !/usr/bin/perl -wl
     
    print "ARGV=\"$ARGV[0] $ARGV[1]\"";
    my $num = @ARGV;
    print "$num";
    $ perl argv.pl arg1 arg2
    ARGV="arg1 arg2"
    2
    Perlの場合は自分自身は引数に含まれない($0を使う)

変数展開

  • AWKではダブルクォートの中での変数展開ができないので、ちょっとややこしい。$ awk 'BEGIN{GUITAR="John";}{ if( $1 ~ "^" GUITAR ) print $0; }' beatles.txt
    John Lennon
  • Perlだとらくちん$ perl -wnl -e 'BEGIN{$guitar="John";}/^$guitar/ and print;' beatles.txt
    John Lennon

その他

  • -i拡張子機能はAWKにはない。
  • セパレータで区切られた文字列を自動的にフィールドに入れる機能はPerlではデフォルト無効。AWKでは常に有効。仮に使わなくても。
  • Perlはモジュールが使える。

AWKのほうが優れている点

  • シンプルなプログラムではサイズが小さくなる。
  • 引数の個数がARGCという変数だけでとれる。Perlは@ARGVをスカラーに一旦入れないといけない。

とりあえずAWKとの違いはこんな感じ。まあgrepやsedに比べるとそれほど大きな差はないけど、AWKでできることは大概できるって感じかな。

次回も引き続き、PerlでAWKの処理をやります。AWKの神髄とも言えるフィールド処理の話です。では。

[メモ] ユーザ権限でホームディレクトリにPerlモジュールをインストール
2008/11/24 22:37 posted by kunkichi

ちょっと訳あってモジュールをrootでインストールできないので、そのメモ。

$ pwd
/home/kunkichi
$ tar zxvf Net-SNMP-5.2.0.tar.gz
$ cd Net-SNMP-5.2.0
$ perl Makefile.PL PREFIX=~/perl
$ make
$ make test
$ make install

使う時。

$ perl -I$HOME/perl/lib/perl5/site_perl/5.8.8 -w -MNet::SNMP -e '〜'

CentOS5.2で試してます。

[時間割:Perl]『ミニマルPerl』その9
2008/11/12 01:48 posted by kunkichi

ここんところちょっと仕事が忙しくて帰ってきたら勉強する気ゼロなことが多いんですが、そんな中最近の一番の勉強スポットはお風呂だったりしてます。いやー、高い本は気を使いますw

ということで、昨日月曜日の『Perl』の時間の成果をアップします。引き続きsed編。sed編はこれが最後です。

ミニマルPerl Unix/LinuxユーザのためのPerl習得法
Tim Maher
オライリージャパン
売り上げランキング: 96883
  • 大文字小文字変換用の文字列修飾子$ echo "abc" | perl -wpl -e 's/^.*$/\U/g;' ← 大文字変換
    ABC
    $ echo "ABC" | perl -wpl -e 's/^.*$/\L/g;' ← 小文字変換
    abc
    あと、\u と \l は隣の1文字だけを変換。
  • \E で \Uや\Lを終了する。$ perl -e 'print "this is \Ucapital\E letters.\n";'
    this is CAPITAL letters.
  • 文字列修飾子は一部のコンテキストでのみ使える。ダブルクォートされた文字列、マッチングや置き換えの場合とか。
  • 置換演算子 e で 置き換えた後の文字列をコードで生成することができる(e は eval の e)これを使えば置換で計算とかができる。$ echo "20 miles 14" | perl -wp -e 's/^(\d+) miles$/$1 * 1.6 . " km"/e;'
    32 km
  • 関数を使って置き換えたり。Text::Tabsのexpand関数を使って、タブを4つのスペースに置き換えてみる。$ echo "this  is  a  tab-separeted sentence." | perl -wp -MText::Tabs -e '$tabstop = 2; s/^.*$/expand $&/eg'
    this  is  a tab-separeted sentence.

次はawkです。これで文字列処理系のコマンドは全部置き換えられちゃうなー。

[時間割:Perl]『ミニマルPerl』その8
2008/11/05 02:49 posted by kunkichi

昨日は祝日で外に遊びにいってたのですが、一応ノルマは守りました。ということで月曜日の『Perl』の勉強成果をアップ。引き続き、sedをPerlで置き換えてみます。

ミニマルPerl Unix/LinuxユーザのためのPerl習得法
Tim Maher
オライリージャパン
売り上げランキング: 96883
  • テンプレート的に使う。以下のようなメールの雛形ファイルがあるとして、From: %%FROM%%<%%ADDR%%>
    To: %%TO%%
    Subject: [%%LEVEL%%] %%SUBJECT%%
     
    %%CONTENTS%%
     
    ------------------------------
    This mail is automatically sent.
    これを置き換えるスクリプトをmake_mail.plとする。内容は以下#!/usr/bin/perl -s -wpl
     
    s/ %%FROM%%     /$from/xg;
    s/ %%ADDR%%     /$addr/xg;
    s/ %%TO%%       /$to/xg;
    s/ %%LEVEL%%    /$level/xg;
    s/ %%SUBJECT%%  /$subject/xg;
    s/ %%CONTENTS%% /$contents/xg;
    で実行するコマンドは以下。$ ./make_mail.pl -from='kunkichi' -addr='kunkichi@example.com' -to='admin@example.com' -level='CRITICAL' -subject='SERVER DOWN!!!' -contents='Server is down at 10:25. Please Check!!!' mail.tpl出力結果:From: kunkichi <kunkichi@example.com>
    To: admin@example.com
    Subject: [CRITICAL] SERVER DOWN!!!
     
    Server is down at 10:25. Please Check!!!
     
    ------------------------------
    This mail is automatically sent.
    -sで引数を変数として取る。正規表現でxを使って正規表現中にスペースを含めるので、読みやすい。ただし、変換前文字だけ。
  • 特殊文字のマッチングを使って変換もできる。8進数→ASCII文字とか、\c制御文字とか。
  • -iを使って、編集元のファイルを直接変換&バックアップ。$ perl -i.BAK -wpl -e 's/aaa/bbb/g;' sample.txtオリジナルファイルは、sample.txt.BAKとしてリネームされて、sample.txtに変換後の結果が上書きされる
  • -iを使う場合は、-p、もしくは-n&printを使わないと、ファイルに何も出力されない、空ファイルができるので、注意!
  • スクリプト化しても便利。#!/usr/bin/perl -s -i.BAK -wpl
    s/$re/$after/g;
    -sでオプションを取ってオリジナルファイルを変換、元ファイルは.BAKをつけてリネーム。
  • 正規表現でx修飾子を使うと、スペースだけじゃなくてコメントも入れれる。s/
      ^          # 行頭が
        aaa     # aaaで始まり
        .*        # 任意の文字が0回以上続いて
        bbb    # bbbで
      $          # 行末が終わる
    /changed/gx; # ところを"changed"に置き換える。
  • -iを使ってバックアップをとっても、同じことを2回実行すると、結局元々のオリジナルは失われてしまう(バックアップがバックアップで上書きされる)。こういう場合は、-iの拡張子に毎回異なるもの、例えばシェル変数で時間とか、を指定すれば何回実行してもOK。例えば$SECONDSで、シェル起動後の秒数とか。$ perl -i.$SECONDS -wpl -e 's/aaa/bbb/g;' sample.txt
  • -iで拡張子を指定する代わりに、-iを単体で使って、$^Iという拡張子を示す特殊変数に拡張子を指定することもできる。例えばPIDとか。#!/usr/bin/perl -i -wpl
    BEGIN{ $^I=$$; }
    s/aaa/bbb/g;
    ただしこれはコマンドラインからの実行では、$$はシェルで展開されてシェルのPIDが入ってくるので、同じシェルで2回実行すると全く意味が無くなる。あくまでもスクリプト内で使う。

sedのところは残り少しです。

[時間割:Perl]『ミニマルPerl』その7
2008/10/31 02:40 posted by kunkichi

今日も外で勉強してきました。やっぱり外はいいですね。ということで木曜日は『Perl』です。今回からsedをPerlで置き換えてみようというところです。

ミニマルPerl Unix/LinuxユーザのためのPerl習得法
Tim Maher
オライリージャパン
売り上げランキング: 96883
  • おなじみの置換。sedとほとんど同じ。$ echo "abcde" | perl -wpl -e 's/abc/ABC/g;'
    ABCde
  • 複数の置換を一気に。まずはsed。これは知らなかった。$ cat example.sed
    s/a/A/g
    s/b/B/g
    s/c/C/g
    $ echo "abcde" |  sed -f example.sed
    ABCde
    これをPerlで。コマンドラインだとこんな感じ。$ echo "abcde" | perl -wpl -e '
    > s/a/A/g;
    > s/b/B/g;
    > s/c/C/g;'
    ABCde
    スクリプトだと以下。$ cat example.pl
    #!/usr/bin/perl -wpl
    s/a/A/g;
    s/b/B/g;
    s/c/C/g;
    $ echo "abcde" | ./example.pl
    ABCde
  • 行を指定して置換。sedの場合。$ cat sample.txt
    This is sentence 1.
    This is sentence 2.
    This is sentence 3.
    $ sed '1s/sentence/REVISED_SENTENCE/g;' sample.txt
    This is REVISED_SENTENCE 1.
    This is sentence 2.
    This is sentence 3.
    Perlだと行番号を表す$.を使う。$ perl -wpl -e '$. == 1 and s/sentence/REVISED_SENTENCE/g;' sample.txt
    This is REVISED_SENTENCE 1.
    This is sentence 2.
    This is sentence 3.
  • -0digitを使って、段落単位、ファイル単位もできる。$ cat sample2.txt
    This is paragraph 1.
    And, this is a sentence for paragraph 1.
     
    This is paragraph 2.
    And, this is a sentence for paragraph 2.
     
    This is paragraph 3.
    And, this is a sentence for paragraph 3.
    $ perl -00 -wpl -e '$. == 1 and s/paragraph/PARAGRAPH/g;' sample2.txt
    This is PARAGRAPH 1.
    And, this is a sentence for PARAGRAPH 1.
     
    This is paragraph 2.
    And, this is a sentence for paragraph 2.
     
    This is paragraph 3.
    And, this is a sentence for paragraph 3.
     
  • 後方参照。sedとPerlだとマッチ部分のカッコのエスケープが逆なので注意。まずsed。$ echo "This is a sample sentence." | sed 's/^\(.*\) \(sentence\.\)$/\1 REVISED \2/g'
    This is a sample REVISED sentence.
    sedはカッコにエスケープをつけると正規表現の部分マッチ用のカッコとなる。次にPerl。$ echo "This is a sample sentence." | perl -wpl -e 's/^(.*) (sentence\.)$/$1 REVISED $2/g'
    This is a sample REVISED sentence.
    Perlの場合は逆にエスケープをつけない場合が正規表現のマッチ用カッコとなる。
  • 行番号で表示を指定。例として2行目以降を出力してみる。$ sed -n '2,$p' sample.txt
    This is sentence 2.
    This is sentence 3.
    Perlだとこんな感じ。$ perl -wnl -e '$. > 1 and print;' sample.txt
    This is sentence 2.
    This is sentence 3.
  • もちろん、さっきとおんなじように、-0digitを使えば、段落単位・ファイル単位とかも可能

sedで後方参照する時っていつもカッコのエスケープ忘れてハマるんだよね、苦笑。行番号の箇所なんかもキー入力はPerlのほうが少し多くなるけど、直感的。

このページの先頭へ