I ♥ WordPress

[時間割: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で試してます。

[メモ] 2進数 ←→ 16進数の計算
2008/11/24 15:19 posted by kunkichi

メモその3。

例1:2進数 10101 を 16進数に。

2進数の4桁が16進数の1桁になるので、最初に対応を確認する。

2進数 16進数
0000 0
0001 1
0010 2
0011 3
0100 4
0101 5
0110 6
0111 7
1000 8
1001 9
1010 A
1011 B
1100 C
1101 D
1110 E
1111 F

10101 = 0001 と 0101

⇒ 15

例2:16進数 AE を 2進数に。

上と同様に対応を見る。

AE = 1010 と 1110

⇒ 10101110

[メモ] 10進数 ←→ 16進数の計算
2008/11/24 14:47 posted by kunkichi

メモその2。

例1:16進数 A5 を 10進数に。

まず、10進数と16進数の対応を確認。

10進数 16進数
0 0
1 1
2 2
3 3
4 4
5 5
6 6
7 7
8 8
9 9
10 A
11 B
12 C
13 D
14 E
15 F

各桁数-1を16の乗数として、それに16進数が対応する10進数をかけたものを最後に足す。

A(10) × 161
5(5) × 160

⇒ 165

例2:10進数 251 を 16進数に。

10進数の数字を16で割っていき、その商が0になるまで繰り返す。各あまりを下から順に並べて、16進数で置き換える。

251 ÷ 16 = 15 あまり 11 (B)
15 ÷ 16 = 0 あまり 15 (F)

⇒ FB

[メモ] 10進数 ←→ 2進数の計算
2008/11/24 14:23 posted by kunkichi

メモ。

例1:10進数 15 を 2進数に。

10進数の数字を2で割っていき、その商が0になるまで繰り返す。各あまりを下から順に並べると10進数になる。

15 ÷ 2 = 7 あまり 1
7 ÷ 2 = 3 あまり 1
3 ÷ 2 = 1 あまり 1
1 ÷ 2 = 0 あまり 1

⇒ 1111

例2:10進数 32 を 2進数に。

32 ÷ 2 = 16 あまり 0
16 ÷ 2 = 8 あまり 0
8 ÷ 2 = 4 あまり 0
4 ÷ 2 = 2 あまり 0
2 ÷ 2 = 1 あまり 0
1 ÷ 2 = 0 あまり 1

⇒ 100000

例3:2進数 10011 を 10進数に。

各桁数-1を2の乗数として、それに2進数をかけたものを最後に足す。

1×24 = 16
0×23 = 0
0×22 = 0
1×21 = 2
1×20 = 1

⇒ 19

[時間割:C言語]『はじめてのC言語完全入門』その11
2008/11/21 22:59 posted by kunkichi

いかんいかん、XBOX360の「FIFA09」が出たせいでサボりまくり、、、
気分を取り直してがんばります。金曜日は「C言語」。今日は文字列です。

はじめてのC言語 完全入門 (標準プログラマーズライブラリ)
塚越 一雄
技術評論社
売り上げランキング: 420963


  • Cには文字列型は存在しない。文字列は文字型の配列を使う。なぜなら可変長だから。
  • 文字列の初期化は以下の数パターン。
    • 文字単位で初期化。#include <stdio.h>
       
      int main()
      {
        char s[5];
       
        s[0] = 'a';
        s[1] = 'b';
        s[2] = 'c';
        s[3] = '\0';
       
        printf("%s\n", s);
       
        return 0;
      }
      ポイントをいくつか。
      • 宣言するときにサイズもあわせて宣言する。サイズは代入したい文字数に1を足しておく。
      • 1を足したのは最後に文字列の終わりを示すEOS(End Of String)の分。EOSにはNULL文字を使う。文字列の場合は\0。
      • printfで出力する場合は%sで配列名を指定する。
    • {}をつかったやり方#include <stdio.h>
       
      int main()
      {
        char s[] = {'a', 'b', 'c'};;
       
        printf("%s\n", s);
       
        return 0;
      }
      この場合はサイズの宣言は不要。よしなにやってくれる。
    • 文字列リテラルで。#include <stdio.h>
       
      int main()
      {
        char s[] = "abc";
       
        printf("%s\n", s);
       
        return 0;
      }
      一番普通。
  • {}を使った場合や文字列リテラルで初期化した場合でもサイズの指定は可能。ただし、EOSの分を足すことを忘れないこと。
  • 同じ文字だけの文字列で初期化する場合は、string.hのmemset関数を使う。#include <stdio.h>
    #include <string.h>
     
    int main()
    {
      char s[4];
     
      memset(s,'a',3);  /* 1: 代入する配列、2:文字、3:文字数 */
      s[3] = '\0';          /* 最後にEOSを代入。面倒、、、 */
     
      printf("%s\n", s);
     
      return 0;
    }
  • 文字列宣言後に文字列リテラルで代入することはできない。その場合はベタに文字配列で要素ごとに代入するか、strcpyを使う(これはまだ先)。文字配列の場合はEOSを最後に代入することを忘れないこと。
  • サイズを超えた場合でも、サイズに見たない場合でも、コンパイラはエラー等を返さないので注意。特に超えた場合は、、、

うーん、やっぱり文字列の扱いは面倒だなぁ、特にサイズを意識しないといけないってのは厳しい。十分に気をつけるようにして次へ進みましょう。次回は「ファイル入出力」。やっと実際のプログラミングらしくなってきました。

[時間割: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です。これで文字列処理系のコマンドは全部置き換えられちゃうなー。

[時間割:C言語]『はじめてのC言語完全入門』その10
2008/11/09 00:27 posted by kunkichi

ここ2、3日格闘していた、ポインタですが、なーんとなく少し壁は超えれたような気がするので、わかってるところだけでもちょっとまとめてみます。あくまでも、なーんとなくのレベル。

はじめてのC言語 完全入門 (標準プログラマーズライブラリ)
塚越 一雄
技術評論社
売り上げランキング: 420963


ポインタ

  • 変数は値を記憶する。ポインタ変数はアドレスを記憶する。
  • 宣言する場合は、変数名の前に*をつける。あと、ポインタにも型は必要。int *pval;
  • ポインタで指定されるアドレスは先頭アドレス。そこから何バイトのデータなのかを判断するために、「型」が必要。(型がわかればバイト数がわかる。sizeof(int)とか)。つまりポインタは型情報を持つということ。
  • ポインタへの代入は当たり前だけどアドレスを代入する。通常はアドレス演算子&を使う。変数に&をつけると、その変数の値ではなく、アドレスを参照する。int *pval;
    int val;
    pval = &val;
  • ポインタがさしている別の変数のアドレスから、値を参照する場合は、*を使って逆参照する。int val = 10;
    int *pval;
    pval=&val;
    printf("%d¥n",*pval);
    結果は”10″が出力される。
  • Cの関数では、実引数の値は仮引数にコピーされるため、関数内でどうこうしたとしても実引数には影響しない。つまり、スコープの話。
  • 関数内で実引数を直接変更したい場合はポインタ引数を使う。
    関数の宣言:void pointer_func( int *x, int *y )関数の呼び出し:pointer_func( &a, &b )関数内で値を参照:int val = *a;
  • アドレスを返すような関数でエラーを返す場合はNULLポインタを使う。

配列とポインタ

  • 配列の名前は、配列の先頭アドレスを意味するので、ポインタに代入できる。int ary[] = { 1, 2, 3 };
    int *pval;
    pval = ary;
  • 配列の先頭アドレスは、配列の最初の要素の先頭アドレスでもある。つまり、ポインタに代入した後、逆参照すれば、最初の要素の値を取得できる。※上の続き
    printf("%d¥n", *pval);
    結果は1となり、ary[0]の値となる。
  • ポインタで演算をすると、そのポインタの型が使用するメモリサイズ分だけ加算される。#include <stdio.h>
     
    int main()
    {
      int *p;
      printf("%p\n", p );
      p += 1;
      printf("%p\n", p );
     
      return 0;
    }
    結果は0x1000
    0×1004
    となる。
  • 上記を配列で使うと、2番目以降の要素の参照ができる。#include <stdio.h>
     
    int main()
    {
      int ary[] = {
        1,
        5,
        8
      };
      int *p;
     
      p = ary;
     
      printf("%p:%d\n", p,   *p     );
      printf("%p:%d\n", p+1, *(p+1) );
      printf("%p:%d\n", p+2, *(p+2) );
     
      return 0;
    }
    結果:0xbffff9f0:1
    0xbffff9f4:5
    0xbffff9f8:8
    アドレスは4バイトずつ(僕の環境では)増えて、配列の要素を順に参照している。
  • 上の例では参照するポインタを直接指定していたけど、ループを使ってポインタの値をインクリメントしながら参照してみる。#include <stdio.h>
     
    int main()
    {
      int ary[] = {
        1,
        5,
        8
      };
      int *p;
     
      p = ary;
     
      int i;
      for( i=0; i<(sizeof ary / sizeof ary[0]); i++ )
        printf( "%d:%p:%d\n", i, p, *p++ );
     
      return 0;
    }
    結果は同じ0:0xbffff9f0:1
    1:0xbffff9f4:5
    2:0xbffff9f8:8
  • ポインタを配列のように使う。上の例のforループの部分を以下のように書き換えてみる。  for( i=0; i<(sizeof ary / sizeof ary[0]); i++ )
        printf( "%d:%p:%d\n", i, &p[i], p[i]);
    結果はこれまた同じ。0:0xbffff9ec:1
    1:0xbffff9f0:5
    2:0xbffff9f4:8
    つまり、配列のようにインデックスで指定して、元の配列要素の値を取得できる。
  • 今度は逆に配列をポインタのように使う。include <stdio.h>
     
    int main()
    {
      int ary[] = {
        1,
        5,
        8
      };
     
      int i;
      for( i=0; i<(sizeof ary / sizeof ary[0]); i++ )
        printf( "%d:%d\n", i, *(ary+i) );
     
      return 0;
    }
    結果はこうなる。0:1
    1:5
    2:8
    配列の各要素に、ポインタで使った逆参照演算子*を使って値を参照することができる。
  • 配列とポインタの違いは、
    • ポインタは変数であり、メモリ上にアドレスを記録するための領域が確保される。従って値を変更することができる。
    • 配列名は、コンパイラがコンパイル中に使用する「定数」なので、メモリ上に配列名を記憶するための領域は確保されない(ただし配列の各要素を記録するための領域は確保される)。従って、値を変更することができない。
  • 関数の引数に配列を渡す場合は配列名だけを渡す。int ary[];
    sample func(ary)
  • 関数側の受け取り方は以下の2パターン。配列の要素から最大値を求めるmaxという関数をそれぞれのパターンで書いてみる。
    • 配列で受け取る。例:
      int sample_function(int a[]){
      ・・・
      }
      サンプルコード:#include <stdio.h>
       
      int max(int a[], int size);
       
      int main()
      {
        int ary[] = {
          1,
          5,
          8
        };
        int val;
        val = max( ary, sizeof ary / sizeof ary[0]);
        printf("%d\n",val);
        return 0;
      }
       
      int max(int a[], int size)
      {
        int max = a[0];
        int i;
        for(i = 1;i<size;i++)
          if(max < a[i])
            max = a[i];
        
        return max;
      }
    • ポインタで受け取る。
      例:int sample_function(int *a){
      ・・・
      }
      サンプルコード:#include <stdio.h>
       
      int max(int *a, int size);
       
      int main()
      {
        int ary[] = {
          1,
          5,
          8
        };
        int val;
        val = max( ary, sizeof ary / sizeof ary[0]);
        printf("%d\n",val);
        return 0;
      }
       
      int max(int *a, int size)
      {
        int max = a[0];
        int i;
        for(i = 1;i<size;i++)
          if(max < a[i])
            max = a[i];
        
        return max;
      }
  • 配列を関数に渡す場合、渡されるのは配列の先頭アドレスだけなので、配列の要素数については別に渡してあげる必要があるので注意。上記の例で、関数の引数に配列だけじゃなくて、配列も渡しているのはそのため。試しに配列の要素数を返す関数を作って試してみる。#include <stdio.h>
     
    int arynum(int a[]);
     
    int main()
    {
      int ary[] = {
        1,
        5,
        8
      };
      int val;
      
      val = arynum( ary );
      printf("%d\n",val);
      printf("%d\n",sizeof ary / sizeof ary[0]);
      return 0;
    }
     
    int arynum(int a[])
    {
      int num;
      num = sizeof a / sizeof a[0];
      return num;
    }
    結果は以下。1
    3

ふぅー、途中ちょっと別の本も読んでみたりしつつでしたが、何度か繰り返し読んで、サンプルコードを自分で書いてみて、そんなこんなしてるうちに何となくわかってきました。やっぱり「何度も読む」ことで見えてこなかったものが少しずつ見えてくるんだよね。とりあえず最大の難関を終えてホッとしました。

次回は「文字列と文字配列」です。

[時間割: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のところは残り少しです。

このページの先頭へ