mond-tech Perl 忍者ブログ
焼肉屋さんが大好きです。いや、そうでも無い。 たぷたぷになってきてピンチです。
19
×

[PR]上記の広告は3ヶ月以上新規記事投稿のないブログに表示されています。新しい記事を書く事で広告が消えます。

コマンドを実行して、標準入力、標準エラー、標準出力などをそれぞれ扱いたい場合に非常に便利な関数。
コマンドを開いてごにょごにょしたい時に必要なものが全て揃ってる。

my $pid;
my $cv = run_cmd [qw(./test.pl)],
'<' => 'stdin.dat',
'>' => 'stdout.log',
'2>' => 'stderr.log',
on_prepare => sub {
print "[ON_PREPARE]\n";
},
'$$' => \$pid;

print "PROCESS_ID: $$\n";
print "SUB_PROCESS_ID: $pid\n";
print 'EXIT CODE: '. ($cv->recv >> 8) . "\n";
print 'EXIT SIGNAL: '. ($cv->recv & 127) . "\n";


なんとも簡単。
on_prepareは、コマンド実行前に叩かれる関数。
$$では、コマンド用のサブプロセスのIDが取れる。

$cv->recvで、コマンドの終了ステータス($?で取れるアレ)が取れる。

test.plはこんな感じ。

#!/usr/bin/perl

print "[STDOUT] HOGEHGOE\n";
print STDERR "[STDERR] FUGAFUGA\n";
while (<>) { print }
exit 1;



my $cv = run_cmd [qw(./test.pl)],
'<' => 'stdin.dat',
'>' => \my $stdout,
'2>' => \my $stderr,
'$$' => \$pid;


スカラーで受ける事も出来るよ。
PR
多重IOをやる場合、何気にいろいろ面倒臭い事があるのだけれど(特にライブラリの依存関係周り)、
そんな悩みを一気に解消してくれるAnyEvent。
とても優れたライブラリなので使い方のメモを公開。

STDINを監視して、任意の秒数後にタイムアウトする、と言うサンプル。
入力が何も無い状態でEnter打たれたら、再び入力を催促。

alarm使った方が、いやむしろ、IO::Promptった方がコードごっそり減るけど、
あくまでAnyEventの書き方のサンプルって事で。AnyEvent::Introのサンプルにもあるしね、これ。


#!/usr/bin/perl

use strict;

use AnyEvent;

my $TIMEOUT = 3;

$| = 1;

my $condvar = AnyEvent->condvar;
my $watcher_stdin = watch_stdin($condvar);
my $watcher_timeout = watch_timeout($condvar);
main_loop($condvar);

sub watch_stdin {
my ($cv) = @_;
print 'INPUT: ';
return AnyEvent->io(
fh => \*STDIN,
poll => 'r',
cb => sub {
my $in = <>;
chomp $in;
if ($in ne '') { $cv->send($in); }
else { print 'INPUT: '; }
}
);
}

sub watch_timeout {
my ($cv) = @_;
return AnyEvent->timer(
after => $TIMEOUT,
cb => sub {
print "\ntimeout\n";
$cv->send('empty');
},
);
}

sub main_loop {
my ($cv) = @_;
print '> ' . $cv->recv . "\n";
}


解かりやすいように凄く大げさに書いた。
と言うか、まともにコード組むと、大概はこんな感じになるはず。

まず、AnyEventでは、ちょっと名前が微妙なcondvarを用いて、通信を行う。
具体的言うと、このcondvarオブジェクトのrecvを呼ぶと、
sendで値が与えられるまで、ブロッキングされる、と言う具合。

watch_stdinでは、io関数を用いてSTDINの監視を設定。
読み込み可能になった場合(つまり入力があった時)に動作する関数を、
cbの値として与える。pollには読み込み時と言う事で'r'。fhにはSTDINのグロブのリファレンス。
これはIO::Handle系のオブジェクトでも良い。
このコールバック関数の中で、STDINに対しての入力が空では無かった場合に、
condvarのsendを叩いて、値を入れる。

watch_timeoutでは、タイムアウトイベントをtimer関数を用いて指定。
afterで、タイムアウトまでの時間を設定。
timerでは、afterで指定した秒数後に、コールバックが実行される。

main_loopでは、condvarのrecvを呼んで、ブロッキング開始。

まぁ、簡単でしょう。

注意点としては、

my $watcher_stdin = watch_stdin($condvar);

こんな感じで、AnyEvent->ioやtimerから返ってくる値を必ず変数で受けること。
こうしないと、正常動作しない。

これは、AnyEventのguardと言うものを用いているから。詳しくは別で説明するけど、
大雑把に言うと、その変数が開放される際に呼ばれるコールバックを設定する事が出来る、と言うもの。
リソース開放系、ですわ。
ググッたら微妙なサンプルしかなかったので、サンプル上げてみる。

use Data::Dumper;
use Email::MIME;
use Mail::POP3Client;

my $pop = new Mail::POP3Client(
USER => "user",
PASSWORD => "password",
HOST => "host",
);

my @ret = ();
for my $n (1..$pop->Count) {
my %r = ();
my $parsed = new Email::MIME(scalar $pop->Retrieve($n));
$r{header} = { $parsed->header_pairs };
$r{body} = $parsed->body;
push @ret, \%r;
}
warn Dumper \@ret;
$pop->Close;

Copyright c mond-tech All Rights Reserved
忍者ブログ / [PR]
にほんブログ村 IT技術ブログ Webサイト構築へ