I ♥ WordPress

[時間割:Perl]『ミニマルPerl』その25
2009/04/07 01:29 posted by kunkichi

月曜日は「Perl」です。前回に引き続きスクリプト編ですが、明日は仕事で朝が早いので、ちょっと軽めで。まあif/elseは普段も普通に使ってるので、ササッとすませちゃいます。

ミニマルPerl Unix/LinuxユーザのためのPerl習得法
Tim Maher
オライリージャパン
売り上げランキング: 96883
  • if/elseのブロックをどう書けば一番読みやすい、かつ、文の構造上意味をよく表すか?というのはずっと考えていたんだけど、やっぱりこれが一番読みやすい気がした。if( ・・・ ){
      真の場合の処理;
    }
    else{
      真の場合の処理;
    }
  • viで括弧にカーソルを併せて”%”を押すと対応する括弧にカーソルが移動する!知らなかった、、、vimならこの手の機能はあるんだろうけど、Solaris標準のviでも使えるかな?
  • ここで紹介されている”cd_report”スクリプトみたいな、複数のカラムを持つリストファイルに対して、複数のコマンドラインオプションで一致するものを表示する、ようなのって、結構使い勝手ありそうだなぁ。明日ちょっとサンプルを作ってみよう。

ということで、ちょい短めですが、今日はここまで。
次回は文字列の連結とか反復とか。

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

木曜日は「Perl」です。前回に引き続きスクリプト編。引数処理のところ。

ミニマルPerl Unix/LinuxユーザのためのPerl習得法
Tim Maher
オライリージャパン
売り上げランキング: 96883

引数の処理(続き)

  • 引数のフィルタ処理
    • 引数に対してフィルタを施してから処理する。前回使ったPerl版grepをもう一度使います。#!/usr/bin/perl -wnl
       
      BEGIN {
        $pattern=shift;
        defined $pattern and $pattern ne "" or
          warn "Usage: $0 'RE' filename\n" and
          exit 11;
      }
       
      /$pattern/ and print "$0:$_¥n";
      第1引数は検索パターンなので$patternに読み込んだ後にshift。残りの引数は検索対象のファイルになるんだけどこれをファイル名で順にソートして処理するようにする。・・・
      BEGIN {
        $pattern=shift;
        @ARGV = sort @ARGV; # ここでファイル名でソート
        defined $pattern and $pattern ne "" or
      ・・・
      で、実行。テスト用にこんなファイルを用意してみた。$ cat 1.txt
      chocolate
      cookie
      banana1
      $ cat 2.txt
      orange
      apple
      banana2
      では”banana”をgrepしてみる。$ ./grep.pl banana 1.txt 2.txt
      banana1
      banana2
      $./grep.pl banana 2.txt 1.txt
      banana1
      banana2
      常に同じ順番で表示されるようになるというわけ。
    • Perlのgrepを使ってフィルタ。ファイルのテストとか。@ARGV = grep { -T } @ARGV;この場合だと引数をチェックしてテキストファイルの引数だけが処理される。
    • 上記のgrepでファイルテストのフィルタを使って、バイナリとテキストを分けてみたり。@txt = grep { -T } @ARGV;
      @bin = grep { ! -T } @ARGV;
    • ファイルグロブを使えば引数自体がいらなくなる。たとえば、カレントディレクトリにある.dat拡張子のファイルでテキストデータのものを取得する@txt_dat = grep { -T } <*.dat>;

最近コマンドラインのツールを作ることが多いので、これはちょっと便利。

次からはif/elseとかの条件分岐です。

[時間割:Perl]『ミニマルPerl』その23
2009/03/30 23:15 posted by kunkichi

最後の更新はもう2週間前、、、やばいやばすぎる、、

ということで久々になってしまいましたが、また時間割再開です。月曜日は「Perl」。えっと、前回に引き続き、スクリプトでよく使う関数のところです。

ミニマルPerl Unix/LinuxユーザのためのPerl習得法
Tim Maher
オライリージャパン
売り上げランキング: 96883
  • shift
    • コマンドライン引数の処理に使う。
    • 複数の引数に対して順次shiftしていくと、引数が順に処理されて破棄される。わかりにくいのでスクリプトで。#!/usr/bin/perl -w
       
      while(@ARGV){
        my $arg = shift @ARGV;
        print $arg . "\n";
      }
      引数をいくつかつけて実行してみる。./shift.pl aaa bbb ccc
      aaa
      bbb
      ccc
      @ARGVをshiftして$argに代入していくと、徐々に@ARGVの要素が減っていくというわけ。
    • $#ARGVを使うとこんな感じ。#!/usr/bin/perl -w
       
      while( $#ARGV ge 0 ){
        print $ARGV[0] . "\n";
        shift;
      }
    • シェルだと$*とか$@とか$#あたりを使っておんなじことができる。
    • Perlの場合は最初の例にあるようにshiftで破棄された値を返して変数に入れたりできる。
    • シェルで”shift 2″のようにずらす個数を指定できるのはPerlだとできない。ずらす分だけshiftを呼び出す必要がある。
    • 最初の例にあるように引数に配列を指定してshiftできるし、複数のスカラーに対してもshiftできる。ちなみに指定しない場合は、スクリプトだと@ARGVでサブルーチンだと@_がデフォルトになる。引数処理に便利なようにできてるね。

では、ここまでやってきた、defined、shift、exitを使ってスクリプトをいろいろ便利にするテクニックを見ていきます。

引数の処理

  • 引数の前処理
    • コマンドラインスイッチをわざわざ-sオプションで指定していたのを、そのまま使えるようにする。本で紹介されているPerl版grepを書き換えていく。元々はこんな感じ。#!/usr/bin/perl -wnl -s
       
      BEGIN {
        $pattern or
          warn "Usage: $0 -pattern='RE' filename\n" and
             exit 255;
      }
       
      /$pattern/ and print;
      実行する場合はこんな感じで変数名を指定していた。$ ./grep.pl -pattern='root' /etc/passwd-sの場合は明確に変数名を指定しないといけないので、例えばgrepみたいに、”grep マッチするパターン ファイル名“みたいな指定は無理。shiftを使ってみる。#!/usr/bin/perl -wnl
       
      BEGIN {
        $pattern=shift;
        defined $pattern and $pattern ne "" or
          warn "Usage: $0 'RE' filename\n" and
          exit 11;
      }
       
      /$pattern/ and print;
      shiftで第1引数はそのままパターンとして読み込んでshift。それ以降はファイル名として処理する。この場合はgrep風に実行OK。
    • あと上記のスクリプトでは、以下も入れている。
      • $patternが「定義されているか?」を明確にチェックするためにdefinedを使用。
      • exitの返り値を独自に設定。

と、途中だけど今日はここまで。引数処理のテクニックはまだ続きます。

[時間割:Perl]『ミニマルPerl』その22
2009/03/17 03:13 posted by kunkichi

またもや1週間、爆。まずい、若干モチベーションも下がり気味、これはちょっとテコ入れが必要。

とりあえず、月曜日は「Perl」です。ここまではワンライナーだったりコマンドラインから実行するようなのが多かったのだけど、今回からはスクリプトを作っていきます。

ミニマルPerl Unix/LinuxユーザのためのPerl習得法
Tim Maher
オライリージャパン
売り上げランキング: 96883

スクリプト向けの関数

  • defined
    • 変数が定義されているかをチェックする。
    • 未定義(NULL)、偽(数値0)、空(文字列”")はそれぞれ区別できる。未定義をチェックするのがdefined。
    • 入力チェック等では意図せずNULLになる可能性があるので、その場合はdefinedでちぇっくすべし。
  • exit
    • スクリプトを明示的に終了する。
    • ENDブロックがある場合は、それを実行してから終了する。
    • exitに引数を指定しない場合はデフォルト0を返す(ちなみにシェルは最後の$?を返す)。引数指定の場合はそれを返す。
    • ちなみにdieはデフォルトで255を返す。(ちなみにBEGINブロックで中止する場合はdieだとと警告が出てしまうので、warn and exit 255のほうがよい。)
    • $!変数でdieの終了値を指定することもできる。

次は引数処理です。

[時間割:Perl]『ミニマルPerl』その21
2009/03/09 23:00 posted by kunkichi

1週間って早いなぁ、先週の更新から既に一週間、またがんばらないと、汗

ということで月曜日は「Perl」。引き続き組み込み関数編。ファイルのグロブから。

ミニマルPerl Unix/LinuxユーザのためのPerl習得法
Tim Maher
オライリージャパン
売り上げランキング: 96883
  • ファイルのグロブ・・・ファイル名をワイルドカード文字で生成する。FNG(File Name Generation)とかともいう。まあ百聞は一見にしかず。
    $ ls
    GeorgeHarrison.txt  JohnLennon.txt    RingoStarr.txt
    JimmyPage.txt    JohnPaulJones.txt  RobertPlant.txt
    JohnBonham.txt    PaulMcCartney.txt
    $ perl -wl -e '@files=<Paul*.txt>; print @files;'
    PaulMcCartney.txt
  • 複数の条件を指定する場合は括弧でくくって、カンマで区切る。出力セパレータを改行にすればこういう風に出力される。$ perl -w -e '$,="\n";@files=( <*John*.txt>, <*Paul*.txt> ); print @files;'
    JohnBonham.txt
    JohnLennon.txt
    JohnPaulJones.txt
    JohnPaulJones.txt
    PaulMcCartney.txt
  • ファイルグロブでは<>を使うけど、Perlでは他の用途でも同じ記号を使うため、例えば以下のようにFNGパターンを変数に入れてそのまま使うとエラーになる。
    $ perl -wl -e '$pattern = "Paul*.txt"; @files = <$pattern>; print @files;'
    readline() on unopened filehandle at -e line 1.
    ファイルハンドルとして認識されてしまう。この場合は<>内の変数名の前後をスペースで囲む。
    $ perl -wl -e '$pattern = "Paul*.txt"; @files = < $pattern >; print @files;'
    PaulMcCartney.txt
  • FNGで使うメタキャラクタはシェルのワイルドカードっぽい。正規表現ではないので注意。もし正規表現を使ってより厳密・正確にしたい場合は、前にやったgrepでコードブロック内にマッチ演算子を指定するやつと組み合わせる。
    $ perl -wl -e '@files=<*Paul*>; print @files;'
    JohnPaulJones.txtPaulMcCartney.txt
    $ perl -wl -e '$,="\n";@files=grep{/^Paul/}<*Paul*>; print @files;'
    PaulMcCartney.txt
    ファイルグロブでざっくり選んだやつをgrepのフィルタでより厳密にって感じ。
  • ファイルを管理するようなUNIXコマンドと同じような関数も用意されている。(chdir、mkdir、rmdir、umask、chmod、chown、などなど)
  • PerlのchownはUID/GID両方を変更できるので、chgrpは存在しない。
  • chmod、chown、unkinkなどは、成功・失敗を返すのではなく、成功したファイル「数」を返すので注意!
  • 組み込み関数全般で、引数の扱いには注意!
    • 括弧なしでも使えるけど、括弧は指定したほうがトラブルが少なくてすむケースもある。
    • 以下のようなパターンだと引数がどの関数に対して渡されるべきなのかをPerlが判断できない。
      $ perl -wl -e '@files=<*Paul*>; print sort @files, "\n";'
       
      JohnPaulJones.txtPaulMcCartney.txt

      改行が@filesの各要素と並列でsortが実行されてしまっている。ただしくは以下。セパレータも使って指定した方がすっきりします。
      perl -l -e '$,="\n";@files=<*Paul*>; print sort (@files);'
      JohnPaulJones.txt
      PaulMcCartney.txt

さて、組み込み関数もこの辺で。次からはいよいよスクリプトを作成していきます。

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

どひゃー。ちょっと忙しくてばたばたしている間にもう3月ですよ、トホホ、、、
そろそろ復活しないと〜、ということで月曜日は「Perl」。前回に引き続き、組み込み関数のところ。

今日はリスト処理に絡む関数を。

ミニマルPerl Unix/LinuxユーザのためのPerl習得法
Tim Maher
オライリージャパン
売り上げランキング: 96883
  • sort
    • リストの要素をソートする。デフォルトはアルファベット順。$ perl -wl -e '$,=" "; @ary=("c","a","d","b"); print sort @ary;'
      abcd
    • sortの後にコードブロックで明示的に並べ替え規則を書くとその規則に従ったソートが行われる。ちなみにデフォルトの場合は、本来は以下のコードブロックになっている。$ perl -wl -e '$,=" "; @ary=("c","a","d","b"); print sort { $a cmp $b } @ary;'
      a b c d
    • 数値の場合のコードブロックは以下。$ perl -wl -e '$,=" "; @ary=(14,100,20,8); print sort { $a <=> $b } @ary;'
      8 14 20 100
    • ちなみにこれを文字列としてコードブロックを書くとこうなる。$ perl -wl -e '$,=" "; @ary=(14,100,20,8); print sort { $a cmp $b } @ary;'
      100 14 20 8
    • コードブロックの動作は以下。
      • ソートする項目を$a、$bとする
      • $a と $b を比較演算子で評価する。左辺が大きい場合は-1、イコールは0、右辺が大きい場合は+1を返す。
      • 上記をもとに $a と $b を入れ替える。
    • randを使った無作為ソートの例。randのロジックをコードブロックに記述する。$ perl -wl -e '$,=" "; print sort { int((rand 2)+0.5) -1 } 1..10;'
      2 1 5 9 6 7 4 10 8 3
      randで-1、0、+1のどれかを返すようにすれば、リストのソート規則がランダムになることを利用している。上の例でもあるけれど、文字列・数値それぞれの場合の並べ替え規則はきちんと定義しないとダメだし、かつ、こういう風に定義すればいろいろできるということ。
    • \Lとかを使って、並べ替え規則時に大文字か小文字に統一してやれば、大文字・小文字の違いを無視するソートとかもできる。$ perl -wl -e '$,=" "; print sort { $a cmp $b } "a".."Z","A".."Z";'
      A B C D E F G H I J K L M N O P Q R S T U V W X Y Z a b c d e f g h i j k l m n o p q r s t u v w x y z
      これがこうなる。$ perl -wl -e '$,=" "; print sort { "\L$a" cmp "\L$b" } "a".."Z","A".."Z";'
      a A b B c C d D e E f F g G h H i I j J k K l L m M n N o O p P q Q r R s S t T u U v V w W x X y Y z Z
  • grep
    • UNIXコマンドのgrepとは異なり、標準入力とかファイルからではなく、リストに対して実実行、コードブロックで条件を記載する$ perl -wl -e '@ary=("John","Paul","George","Ringo");print grep {/^J/} @ary;'
      John
  • join
    • リストの要素を単一のスカラに結合する。$ perl -wl -e 'print join "|", "a".."Z";'
      a|b|c|d|e|f|g|h|i|j|k|l|m|n|o|p|q|r|s|t|u|v|w|x|y|z
    • リストに対してマッチングとか置き換えを実施したい場合、個々の要素に対して実施する場合は個別に処理するしかないけど、複数の要素にまたがった状態に対して実施する場合はjoinで結合しちゃうという手が使える。$ perl -wl -e '$str = join "", "apple","monday"; $str =~ /lemon/ and print "Lemon was found!"'
      Lemon was found!
    • -aオプションでフィールド処理した@Fをjoinすると、セパレータの変換的なこともできる。$ cat /etc/passwd | perl -wnlaF":" -e 'print join "|", @F;' | grep -v "^#"
      nobody|*|-2|-2|Unprivileged User|/var/empty|/usr/bin/false
      root|*|0|0|System Administrator|/var/root|/bin/sh
      ・・・
  • map
    • リストを変換するフィルタ。
    • 使い方はgrepと似ているけど、grepはコードブロックの評価に対して各要素を返すのに対して、mapはコードブロックの評価そのもの、つまり変換した結果を返す。$ perl -wl -e '@ary=("John","Paul","George","Ringo"); $,=" "; print map { "\U$_" } @ary;'
      JOHN PAUL GEORGE RINGO
    • ありがちなミス。$ perl -wl -e '$,=" "; print map { s/^(.)/\L$1/g } @ARGV;' 'John' 'Paul' 'George' 'Ringo'
      1 1 1 1
      これはs/〜/〜/gという置換演算子は、置換後の結果を返すsedコマンドとは異なり、置換に成功した数を返す。また、mapのコードブロックで返されるのは、コードブロック内の最後の処理になるため、置換に成功した数として1がかえってきているという訳。これを回避するには、コードブロックの処理の最後に$_をつけてやる。$ perl -wl -e '$,=" "; print map { s/^(.)/\L$1/g; $_ } @ARGV;' 'John' 'Paul' 'George' 'Ringo'
      john paul george ringo

こういうリスト関連処理って、読み込んだファイルの内容をいったんリストに放り込んどいて、まとめてフィルタ、みたいな感じで使えばかなり便利な気がします。

今日はここまで。

[時間割:Perl]『ミニマルPerl』その19
2009/02/13 02:08 posted by kunkichi

木曜日は「Perl」です。引き続き、組み込み関数いろいろ。

ミニマルPerl Unix/LinuxユーザのためのPerl習得法
Tim Maher
オライリージャパン
売り上げランキング: 96883
  • chomp
    • おなじみchomp。これまでは-n や -p に併せて -l オプションを使ってきたので自動的にchompしていたようなもの。
    • ただし、以下のような場合は、-lオプションが聞かないのでchompしないとダメ。$input = <STDIN>;ユーザからの入力内容を標準入力で受け付けるような場合は、最後の改行をchompしてやる必要がある。
    • 配列をchompすると、すべての要素に対してchompできる。
    • chomp の引数に「複数」の引数を指定する場合は、()が「必要」。chomp ( $a, $b );
  • rand
    • 乱数生成。引数なしだと、1以下のものすごく細かい浮動小数点数を返す。$ perl -w -e '$num = rand; print $num;'
      0.179432431775243;
    • 普段はここまではいらないので、引数で倍率を指定する。100だと、100以下の浮動小数点数ということになるので、多少大きくなる。$ perl -w -e '$num = rand 100; print 97.8164008892239
    • 整数で計算したければ(というかこれが一番よく使われるはず)、intで整数にキャストして小数点以下を切り落として使う。$ perl -w -e '$num = int (rand 100) + 1 ; print $num;'
      75
      この例だと、1〜100の間でランダムな数字が選ばれる。

ちょっと短いけど今日はここまで。

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

何事もなかったかのように進めます(笑)月曜日は「Perl」の時間。引き続き、組み込み関数をいろいろ見ていきます。

ミニマルPerl Unix/LinuxユーザのためのPerl習得法
Tim Maher
オライリージャパン
売り上げランキング: 96883
  • statを使っていろいろファイルの情報を取ってみる。
    • 一般的な使い方my @stats = stat "sample.txt";
      0 ファイルシステムのデバイス番号
      1 i ノード番号
      2 ファイルの権限
      3 ファイルへのハードリンク数
      4 ファイル所有者のユーザID
      5 ファイル所有者のグループID
      6 デバイス識別子
      7 ファイルのサイズ(バイト)
      8 最終アクセス時刻
      9 最終変更時刻
      10 最終 i ノード変更時刻
      11 標準ブロックサイズ
      12 ファイルに割り当てられているブロック数
    • 括弧で括ってそれに対して添字でアクセスすることもできる。print (stat "sample.txt")[7];
  • シェルの”-nt”をPerlで書く。っていうか”-nt”って知らなんだ、ファイルのmtimeを比較する演算子(newer thanの略)。これは便利だね。
    まずはシェルの場合。ls -lt sample*txt
    -rw-r--r--  1 kunkichi  staff  48  1  9 00:07 sample.txt
    -rw-r--r--  1 kunkichi  staff  62  9 16 23:04 sample2.txt
    $ [[ "sample.txt" -nt "sample2.txt" ]] && echo "sample.txt"
    sample.txt
    次にPerl。$ perl -e '(stat "sample.txt")[9] > (stat "sample2.txt")[9] and print "sample.txt\n";'
    sample.txt
  • ただし、statは実行ユーザの権限に従うので、ファイルの権限がない場合等を考慮して、ファイル単位で処理するほうがよい。$! で OSエラーメッセージを取ってみる。$ perl -e '$mtime1 = (stat "sample3.txt")[9] or die "cannot stat \"sample.txt\": $!";'
    cannot stat "sample.txt": No such file or directory at -e line 1.
  • lsをPerlで書いてみる。僕のMacだとこんな感じに表示される。$ ls -lt sample.txt
    -rw-r--r--  1 kunkichi  staff  48  1  9 00:07 sample.txt
    Perlで書く場合は、Stat::lsModeを使って、パーミッションの表示をlsコマンドと同じにしてみる。#!/usr/bin/perl -w
     
    use strict;
    use Stat::lsMode;
     
    my $filename = $ARGV[0];
     
    my @stats = stat $filename;
    my $mode  = format_mode $stats[2];
    my $nlink = $stats[3];
    my $uid   = getpwuid $stats[4];
    my $gid   = getgrgid $stats[5];
    my $size  = $stats[7];
    my $mtime = localtime $stats[9];
     
    printf"%s %d %s %s %d %s %s\n", $mode, $nlink, $uid, $gid, $size, $mtime, $filename;
    実行結果は以下。$ ./ls.pl sample.txt
    -rw-r--r-- 1 kunkichi kunkichi 0 Mon Feb  9 23:27:26 2009 sample.txt
    getpwuid、getgrgidは組み込み関数で、UID、GID
    からユーザ名、グループ名に変換する。format_mode でls風の出力に変換。
  • シェルでファイル演算子を使う場合、ファイル演算子は引数にファイル名を取るので、条件節で同じファイルにいろんな条件チェックをする場合は以下となる。[[ -f "sample.txt" && -r "sample.txt" && -s "sample.txt" ]]これでは面倒なので、Perlではstatやファイル演算子で使用された、「最後」のファイル名を”_”(アンダースコア)で参照できる。ただし同じブロック内のみ。-f "sample.txt" and -r _ and -s _statの場合はこんな感じ。(stat "sample.txt")[9] == (stat _)[10]
  • statを使うときは perldoc -f statを実行して、コピペして楽しよう。($dev,$ino,$mode,$nlink,$uid,$gid,$rdev,$size,$atime,$mtime,$ctime,$blksize,$blocks) = stat($filename);

今日はここまで〜。

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

2月になりました。今月もがんばりすぎないようにがんばります。それが長く続けるコツ。

それはそうと、今日仕事帰りに本屋に寄ったら、こんなんが出てました。

さすが!と言わせる Plagger徹底攻略術
蒲生 睦男
シーアンドアール研究所
売り上げランキング: 42881

流行ってたのって一昨年ぐらいじゃなかったっけ?(笑)でもまあ書籍としてまとめられたものはないので、とりあえず買っときました。『ミニマルPerl』早く終わらせて次はこれだな。

ということで続き。今回まではワンライナー的なものや、grep や awk とかを Perl で実装してみる、って感じでしたが、少しプログラミング寄りになっていきます。

ミニマルPerl Unix/LinuxユーザのためのPerl習得法
Tim Maher
オライリージャパン
売り上げランキング: 96883

組み込み関数

  • 評価コンテキスト
    式の使われ方によって、スカラーコンテキストで評価するのか、リストコンテキストで評価するのか。
    例1: 配列をリスト変数、すなわち、配列のコピーとなる。(リストコンテキスト)@list = @F;例2: 配列の要素数をスカラーで代入(スカラーコンテキスト)$num = @F;例3: 配列の各要素をスカラーに代入。(リストコンテキスト)($num1, $num2) = @F;例4: 配列の各要素を順に表示する。(リストコンテキスト)print @list;例5: scalarを使って意図的にスカラーで出力する。(スカラーコンテキスト)print scalar @list;例6: スカラーとして使用される演算子を式で使う。(スカラーコンテキスト)if( @ARGV > 3 ){ ・・・ };例7: 配列の要素を指す場合の添字として使う。$F[@list] = "added";つまり、これだと配列の最後に新しい要素を追加したのと同じになる。
  • リストからスカラーの変換
    • 上で上げたscalarを使うmy @list = ("John","George","Paul","Ringo");
      print scalar @list;
      結果:4この場合は要素数になる。
    • ダブルクォートする。my @list = ("John","George","Paul","Ringo");
      print "@list";
      結果:John George Paul Ringoこちらの場合は各要素をスペースでつなげた一つの文字列となる。
    • joinを使う。これは後ほど。
  • スカラーからリストへの変換
    • splitを使う。my $str = "John Paul George Ringo";
      my @member = split /\s+/, $line;
      一つ以上のスペースで文字列を区切って、各要素に代入。
      引数の順序に注意。最初の引数は区切りとする正規表現の指定。なければ「語」単位。2番目の引数で分割対象となる文字列を指定する。なければ$_。
    • これまでにやってきた、-wnlaとか-wplaとか。
  • localtimeを使って結果をスカラーとリストで取ってみる。
    • スカラーに代入すると、dateコマンドと同じようなフォーマットになる。my $str = localtime();
      print $str;
      結果:Mon Feb  2 23:07:37 2009scalarを使うともっと単純に書ける。print scalar localtime;
    • 単純にprintするだけだと、リストコンテキストで区切り文字がなく出力されるのでわかりにくいです。。。print localtime;結果:231123211091320この場合はリストに出力してやる。my ($sec,$min,$hour,$dayofmonth,$month,$year,$dayofweek,$dayofyear,$dst) = localtime;
      print $year + 1900 . "/$dayofmonth/$dayofmonth $hour:$min\n";
      結果:2009/2/2 23:16もしくは配列の添字でアクセスする。my $hour = (localtime)[2];
      print "This is $hour o'clock.\n";
      結果:This is 23 o'clock.
    • 上のをいちいち入力するのも覚えるのも面倒なので、perldocで調べるとコピペできる。# perldoc -f localtime・・・
      #  0    1    2     3     4    5     6     7     8
                         ($sec,$min,$hour,$mday,$mon,$year,$wday,$yday,$isdst) =
                                                                     localtime(time);
      ・・・

ま、この辺は日常のスクリプトでも結構使うので普通だね。とりあえず今日はここまで。

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

ちょっと間が空いちゃったけど、木曜日は「Perl」の時間。引き続きfind編です。

ミニマルPerl Unix/LinuxユーザのためのPerl習得法
Tim Maher
オライリージャパン
売り上げランキング: 96883
  • パイプの代わりに、バッククォートを使ったコマンド置換で、ファイル名を引数に取るようなところでもPerlは役に立つ。# grep 'John' `ls -d * | perl -wnl -e '-T and print;'カレントにあるディレクトリ・ファイルの一覧(ディレクトリの中身は含まない)からテキストファイルであるものを出力し、それらのうち、’John’を含む行を抽出している。
  • これをファイル形式で書くとこんな感じ#!/usr/bin/perl -s -wnl
     
    BEGIN {
      @ARGV and $re or
        warin "Usage: grep_text -re='REGEX' filen1 [file2, file3, ・・・]
        and exit 255;
     
    -T $ARGV or close ARGV and next;
     
    /${re}/i and  print "$ARGV: $_";
    引数 -reで検索したい表現を指定。ファイルがテキストファイルでなければcloseして次のファイル、テキストファイルであれば、引数で指定された表現が含まれているかをチェックして、含まれていればファイル名とその行を表示する。
    こういうcloseの使い方を覚えないとね。
  • 最初のコマンドのケースをfindのように再帰的にするならば# grep 'John' `find . -type f -print | perl -wnl -e '-T and print;'
  • 引数がファイル名でない場合でも、バリデーションの目的でPerlを使うのも有用。引数のためのプリプロセッサという感じ。
  • find で抽出したファイルに対して何かコマンドを実行したい場合は-execを使ったり、# find . -type f -exec rm {} ¥;とか# find . -type f | xargs rm とかでできるが、それぞれ問題がある。
    • -execの場合はコマンドのプロセスがfindの抽出結果分だけ起動する。
    • xargsの場合は1回のパイプで渡せる上限の数で渡すので、コマンドのプロセスは節約できるが、たとえば以下のケースだと、# find . -type f | xargs sort | tail -1もしfindの数が1回のパイプの上限を超えていた場合は、分割された「まとまり」単位でsortが実行されるため、全体をsortした結果の最新(最後の1行)にはならなかったりする。
  • Perlだとこれを回避できる。以下サンプルスクリプト。#!/usr/bin/perl -wnl
    BEGIN{ $latest_modified=0; }
    $mtime = (stat $_)[9];
    if( $mtime > $latest_modified ){
      $last_modified = $mtime;   ※ここで最新のファイルのタイムスタンプが保持される。
      $last_modified_file = $_;   ※ここで最新のファイルのファイル名が保持される。
    }
    END{
      print $name;
    }
    まあプログラミングらしく、最新のタイムスタンプを変数に記録しておいて、それと比較して最も最近のものの情報(ファイル名、タイムスタンプ)を常に更新するような仕組みにすればよいということだね。
  • あとxargsだと空白文字を含む引数は別々の引数として処理されしまう。Perlだと空白を区切りとして分割させないこともできる。# find . -type f | perl -wnl -e 'print -s,  " $_";

grepやawkの置き換え、だけでなく、今回のfindのように、組み合わせて有効に使えるというのもPerlのよいところだね

これでfindも終わりました。

次回はこれまでのコマンドよりの部分から、もう少しプログラミングに近いところのお話。

このページの先頭へ