»Perlはてなブックマークに追加はてなブックマークを見る

Perlに関するTips。 (時たま使う必要に迫られるが、そのときには忘れているのでメモ)

»シグナルを受信する

sub handler{
    print "signal received\n";
    exit(0);
}

$SIG{'INT'} = \&hander;

sleep(5);

exit(0);

sleep中にCtrl+Cを入力すると、SIGINTシグナルを受信してhandlerが呼ばれる。 'DEFAULT'を設定すると標準のハンドリング処理となり、'IGNORE'を設定するとシグナルを無視する動作となる。 また、ハンドラはリファレンスではなく関数の名前を文字列で指定することもできる。

»ミリ秒単位の精度でsleepする

# 500ミリ秒sleepする
select( undef, undef, undef, 0.5 );

selectのタイムアウト時間は秒未満の精度で指定できる。 また、タイムアウト時間以外のパラメータをundefとすることでタイムアウトのみが動作するようになるため、これによりsleep相当の処理となる。

»実行ユーザがrootかどうか調べる

if ( $> == 0 ) {
  print "user is root.\n";
}
else {
  print "user is not root.\n"
}

特殊変数$>を参照することで現在のユーザIDを参照できる。 ユーザIDが0ならrootユーザ。

»正規表現とのマッチング

$text = "abcdefg";

if ( $text =~ /^abc.*/ ) {
  # 正規表現にマッチする
  print "\$textは先頭がabcで始まる文字列\n"
}

if ( $text !~ /^xyz.*/ ) {
  # 正規表現にマッチしない
  print "\$textは先頭がxyzではない文字列\n"
}

»マッチ式内に変数を展開する

# 除外する文字列
$exclude_regex = "hoge|test|temp";

@list = (
  "hogehoge",
  "sample",
  "test1",
  "2test",
  "template",
  );

foreach $val ( @list ) {
  # 除外する文字列で始まる値以外を表示する
  if ( $val !~ /^($exclude_regex).*/o ) {
    print "$val\n";
  }
}

実行結果

sample
2test

マッチ式のオプションにoを指定することで、マッチ式内の変数を1度だけ(once)しか評価しないようにする。

»パスからファイル名のみ取り出す正規表現

@paths = (
  "/usr/local/bin/perl",
  "/home/santamarta/test.pl",
  "./../test.pl",
  );

foreach $path ( @paths ) {
  $filename = $path;
  $filename =~ s/^([^\/]*\/)*([^\/]+)$/$2/g;
  printf( "%s -> %s\n", $path, $filename );
}

この正規表現では/usr/local/bin/のように/で終わる場合は正しく動作しない。

»ディレクトリを再帰的に走査する

sub parseDirectoryRecursive {
  my $dir = $_[0];
  my @entries = ();

  opendir( DIR, $dir ) or die "opendir failed";

  # ディレクトリ内のエントリを読み出す
  @entries = readdir( DIR );

  closedir( DIR );

  foreach $entry ( @entries ) {
    if ( $entry ne '.' && $entry ne '..' ) {
      $path = $dir . '/' . $entry;
      print  $path . "\n";

      if ( -d $path && !-l $path ) {
        # ディレクトリ(シンボリックリンクを除く)の場合
        &parseDirectoryRecursive( $path );
      }
    }
  }
}

# カレントディレクトリ以下を再帰的に走査する
&parseDirectoryRecursive( "." );

»システムコマンドを実行する

方法1

print `ls -l`;

方法2

system( "ls -l" );

»独自に定義した比較順序でソートを行う

# ソートを行う際に使用する比較処理
sub comparer() {
  # 文字列の長さで比較する
  return length( $a ) - length( $b );
}

@list = ( "abc", "x", "opqr", "nm", "hijkl" );

# ソート前
foreach $val ( @list ) {
  print $val . "\n";
}

print "\n";

# comparerを用いてlistの内容をソートする
@sorted = sort comparer @list;

# ソート後
foreach $val ( @sorted ) {
  print $val . "\n";
}

実行結果

abc
x
opqr
nm
hijkl

x
nm
abc
opqr
hijkl

sort関数に比較用関数を指定することで、独自に定義した比較順序でソートを行うことが出来る。 ちなみに、sort関数に指定する比較処理は、次の例のように直接記述することも出来る。

@sorted = sort { length( $a ) - length( $b ) } @list;

»Net::FTPを使わずにFTP操作

Net::FTPなどを使わずに、ftpコマンドを使用することでFTP操作を行う方法。

# ホスト、ユーザ名、パスワード
$host = "192.168.0.1";
$user = "santamarta";
$passwd = "password";

# FTPコマンド
$ftp = <<ENDOFFTP;
open $host
user $user $passwd
ls -l
bye
ENDOFFTP

# FTPコマンドを実行
@result = `ftp -n << $ftp`;

# 実行結果を表示
print @result;

»ファイルテスト演算子

if ( -e $file ) {
  print "ファイルは存在します\n";
}

ファイルテスト演算子の後ろには、ファイルハンドルかパスを指定する。

その他のファイルテスト演算子。

-e
ファイルがあるかないか
-f
ファイルかどうか
-d
ディレクトリかどうか
-l
リンクかどうか

否定の!はファイルチェック演算子の前に付ける。

if ( !-e $file ) {
  print "ファイルは存在しません\n";
}

»配列の一番最後のインデックスを取得する

@list = ( "abc", "123", "XYZ" );

printf( "last index of \@list is %d\n", $#list );
printf( "last entry of \@list is %s\n", @list[$#list] );

実行結果

last index of @list is 2
last entry of @list is XYZ

$#配列名とすることで配列の一番最後のインデックスを取得することができる。

»複雑な構造のハッシュを定義する

%userlist = (
  # ID               # Fullname      Password
  "santamarta"  =>  ["santa marta", "password"],
  "hoge"        =>  ["hoge hogeo", "hogehoge"],
  "dummy"       =>  ["dummy", "dummy"],
);

foreach $key ( keys %userlist ) {
  printf( "ID: %s(%s) Password: %s\n",
           $key,
           $userlist{$key}[0],
           $userlist{$key}[1] );
}

実行結果

ID: santamarta(santa marta) Password: password
ID: dummy(dummy) Password: dummy
ID: hoge(hoge hogeo) Password: hogehoge

»サブルーチンとリファレンス

sub routine1 {
  print "routine1\n";
}

sub routine2 {
  print "routine2\n";
}

sub routine3 {
  print "routine3\n";
}

# サブルーチンへのリファレンスを格納するための配列
@routines = (
    \&routine1,
    \&routine2,
    \&routine3,
);

# 配列に含まれる個々のサブルーチンを呼ぶ
foreach $routine ( @routines ) {
  &$routine();
}

»tail -fする

File::Tailがない状況でtail -fと同様の動作を実現する方法。

# ファイルを開く
open( INPUT, "<$ARGV[0]" ) or die;

# ファイルの末尾まで移動する
seek( INPUT, 0, 2 );

# ファイルの監視を開始する
while ( 1 ) {
  # 一行ずつ読み込み続け、表示する
  while ( <INPUT> ) {
    print $_;
  }

  # 50ミリ秒待って再度読み込む
  select( undef, undef, undef, 0.05 );
}

ファイルの終端までひたすら読み続けることで、tail -fと同様の動作を実現する。 待機時間(この例では50ミリ秒)はファイルが更新される間隔にあわせて調節する。

»文字コードを取得する

Jcodeを用いる場合。 $encodingには$textの内容に応じて'euc', 'sjis', 'utf8'などの文字列が格納される。

use Jcode;

my $encoding = Jcode::getcode( $text );

Encode::Guessを用いる場合。 $encodingには$textの内容に応じて'euc-jp', 'shiftjis', 'utf8'などの文字列が格納される。

use Encode::Guess;

my $encoding = guess_encoding( $text, qw/ shiftjis euc-jp / );

Sponsored Link