どんなことでも

この人 blog を書くのだろうか?

perl Expect

2007-12-13 22:07:26 | perl
perl の Expect を使ってみた。でも、動作ログが取れません。マニュアルのリファレンス部分には
$object->log_file("filename" | $filehandle | \&coderef | undef)
と書かれていて、ファイルハンドルを使えるように読める。だが、例の部分には
 1. ファイル名を直接渡す方法」
 3. 関数を呼ぶ方法
 4. 出力を解除する方法
が載っているが、
 2. ファイルハンドルを使う方法
だけ書かれていない。試しに書いてみると
#! /usr/bin/perl -Tw

use lib qw(...略...);

require 5.6.0;
use Expect;
use strict;

$ENV{PATH} = "/bin:/usr/bin";

# log ファイルを開く
open($main::LOG, '>', "log_log");
printf "ref \$main::LOG is %s\n", ref $main::LOG;

my $exp = Expect->spawn("ls", "-l") or die "Cannot spawn ls: $!\n";

# $exp->debug(3);
# $exp->exp_internal(1);
$exp->expect(3 , # timeout
[
qr/.*/s => sub {
$exp->log_file($main::LOG);
$exp->print_log_file("--- ls command. ---");
$exp->send("ls\n");
exp_continue;
}
],
[ timeout => sub { print "timeout?\n"; } ],
);
これを実行
> ./test
ref $main::LOG is GLOB
Given logfile doesn't have a 'print' method at ./test line 22
Exit 255
駄目じゃん。
ソースを見ると、ref($file) が 'CODE' だとファイルハンドルと認識するようだが、私のファイルハンドルは GLOB となっている。
う~ん、CODE って何? GLOB って何?(「型グロブ」の「グロブ」?型グロブって何?) という状態で数時間固まっております。
さて、ファイル名を与えると正しく動くことは確認済みなんだが、どうするかなぁ。ファイルハンドルを持ち回した方が使いやすそうなのだが。
誰か教えて~。昔入っていた perl な ML が分からなくなってしまいました。

最新の画像もっと見る

10 コメント

コメント日が  古い順  |   新しい順
Unknown (kiyoji)
2007-12-14 16:14:35
これって、expectでls -laの結果をlog_logに書き出すんですよね?

そしたら、シェル(bashとか)をspawnしたらどうでしょう?以下のような感じで。
------------
#! /usr/bin/perl -w

use Expect;
use strict;

$ENV{PATH} = "/bin:/usr/bin";

# logファイル名
my $log = "log_log";

# bashをspawnす
my $expect = Expect->spawn("/bin/bash")
or die "Error: Couldn't start program: $!\n";
# STDOUTをオフ
$expect->log_stdout(0);
# logファイの指定
$expect->log_file($log);
# log書き出し
$expect->print_log_file("--- ls command. ---");
# ls -laを打ってみ
$expect->send("ls -la\r");
# タイムアウト1秒で、promptが戻のを捕らえる
$expect->expect(1,qq/.+\$ / );
# exitでbashを閉じ
$expect->send("exit\r");
$expect->soft_close();
$expect->hard_close();

------------
返信する
Unknown (1円切手)
2007-12-14 16:23:08
成る程、
実際には ssh で 3段ぐらい入って、各サーバーで xxx コマンドの結果を集める。(df とか etc etc...)
みたいなことがやりたいので。

$expect->log_stdout(0);
は、確か画面に stdout が出なくなったと記憶していますが、出力先がログファイルに切り替わるのでしょうか?
そうそう、stdout がログファイルに書かれないのも「何でじゃ~」と思ってました。
# ちょっと作業中なので、後で確認します。
返信する
Unknown (kiyoji)
2007-12-14 20:36:49
あ、
$expect->log_stdout(0);
としたのは、単にlogに書き出す指定が
あったので、プロンプトに出さなくても
いいかと思ったので、そうしました。
STDOUTに出したいときは、
$expect->log_stdout(1);
ですね。

sshで入って・・・とのことなので、
spawnをsshに指定すれば出来ますよ~
返信する
Unknown (1円切手)
2007-12-14 21:04:19
意味不明な事をやっていることに気づいた今日この頃。
ls コマンドを spawn してから、それに ls コマンドを投げている。
う~ん、バカσ(;_;)
返信する
Unknown (1円切手)
2007-12-14 21:31:57
#! /usr/bin/perl -Tw

use lib qw(略);

use Expect;
use strict;
use diagnostics;
use warnings;

$ENV{PATH} = "/bin:/usr/bin";

my $LOG = "log_log";
my @option = ("-l", "ossan", "bun");
my $PASSWORD = "menesis";

my $exp = Expect->spawn("ssh", @option) or die "Cannot spawn ls: $!\n";
$exp->log_stdout(0);

$exp->expect(3 , # timeout
 [ qq/password:/ => sub {
  $exp->send("$PASSWORD\n");
  exp_continue;
 } ],
 [ qr/login.*]>/s => sub {
  $exp->log_file($LOG, "a");
  $exp->print_log_file("--- Host: xxx ---\n");
  $exp->send("df -h ; echo df done.\n");
  $exp->print_log_file("-----------------\n\n");
  $exp->log_file(undef);
  exp_continue;
 } ],
 [ qq/df done./ => sub {
  $exp->send("exit\n");
  exp_continue;
 } ],
 [ eof => sub {
  print "Connection close?\n";
 } ],
 [ timeout => sub { print "timeout?\n"; } ],
);
@@@@@@@@@@@@@
とすると、
> cat log_log
--- Host: xxx ---
-----------------
@@@@@@@@@@@@@
実行はされているのですが、ログが出ませんねぇ。
謎。spawn sh してから、send ssh ... でもやっぱり同じ。う~ん、expect の中でオートパイロットのようなことをするとログが取れないということか。まぁ、今回は必要ないから良いかな。
返信する
Unknown (1円切手)
2007-12-14 21:37:58
ということで、kiyoji さんが最初に提示された
spawn で起動
expect で待つ
send でコマンドを送る
expect で待つ
send でコマンドを送る
expect で待つ
...
という方式を採用です。
どうもありがとうございました。 > kiyoji さん
返信する
Unknown (1円切手)
2007-12-14 22:26:19
log に出ないのは、df の結果(stdin)を expect が読んでいないからでした。
なので、
 $exp->log_file(undef);
を、df の結果を読み込んだ後の
 $exp->send("exit\n");
の前に置くと上手くいきました。
返信する
Unknown (kiyoji)
2007-12-17 12:42:32
お、うまく行ったようですね。
なによりです。
Expectは、中々便利なので、Mechanizeと
並んで無人君を作るときに私も割りと使っています。
実行結果の取得が
$expect->before();
で、出来たりするので、結果の値を
加工するときなんかオススメです。
返信する
Unknown (1円切手)
2007-12-17 14:28:18
> 無人君を作るときに私も割りと使っています。
同業者の方のようで(^^;;;
> $expect->before();
ですか。ちょっと試してみます。
返信する
Unknown (1円切手)
2007-12-17 17:09:33
> $expect->before();
なるほど、部分的にログを取るならこれで良いのでは?ということですね。
で、こいつもやっぱり
$exp->send("df -h ; echo df done.\n");
$exp->after();
と続けて書いても駄目っぽく。
$exp->send("df -h ; echo df done.\n");
$exp->expect($timeout, "foo");
$exp->after();
と、しないといけない模様。でも、一々部分的に open/close するよりは、最初に open して print LOG $exp->after(); が分かりやすいですね。(エコーバックもちょっと少ないし)
返信する

コメントを投稿