Hatena::Groupmoti

expect

expect

expect

目次

  • expectとは
  • 使い方
    • 全体のソース
    • シェルスクリプトの基本
    • 変数を作ってexpectを開始する
    • expectの動きを予想してみる
    • 質問の内容を確認し正規表現で書く
  • 実行

expectとは

  • 対話型プログラムに対応したシェルスクリプトを作るときに使う.*1
  • 表示された文字列に対応してコマンドを入力する

使い方

実際のソースを使いながら解説.

全体のソース

#!/bin/sh
NO=2
MAIL=foo@bar.com

expect -c "
set timeout 20
spawn ./setiathome
set timeout 10
expect "*choice*:" { send "$NO"\n}
expect "*address*" { send "$MAIL"\n}
expect "*file." {send exit }
"
./xsetiathome

シェルスクリプトの基本

#!/bin/sh||

頭にこれを書くとシェルスクリプトになる.

変数を作ってexpectを開始する

NO=2
MAIL=foo@bar.com

expect -c "
set timeout 20
spawn ./setiathome
set timeout 10
NO=2
MAIL=foo@bar.com

なにか変更があった場合メンテナンスしやすいように入力文字列は変数に格納しておく.


expect -c "

で開始して,「"」で囲んである間のコードがexpectによって制御される.*2


set timeout 20
spawn ./setiathome
set timeout 10

「timeout」は指定した秒数返事が無ければ終了する.

「spwan」で制御するプログラムを起動する.

ふたたびタイムアウトチェック.

expectの動きを予想してみる

expectを使ってみたところ動きを想像してみると.

expect内でspawnによって実行されたプログラムが吐き出す文字列をexpectは常に監視していて,表示されるテキストにユーザ指定した特定の文字列が出現した場合に用意されたコマンドを入力する*3

という感じ.

そうなるとまずは「出てくるであろう質問を特定し指定する」ことから始めなければならない.

今回は「setiathome」という宇宙人を探すソフトのインストールを例に進めてきた.setiをインストールするには

  1. 登録済みかどうかを入力する(1or2)
  2. 登録済みであった場合メールアドレスを入力する(foo@ber.com)

という手順を踏む.

質問の内容を確認し正規表現で書く

次はソースの、

expect "*choice*:" { send "$NO"\n}
expect "*address*" { send "$MAIL"\n}
expect "*file." {send exit }

この部分を書いていく。


実際にsetiを実行してみるとこんな文字列が返される.

$./setiathome

New software version - deleting temp files.
SETI@home client.
Platform: i686-pc-linux-gnu
Version: 3.08

長いので省略。

Welcome to SETI@home.
We use your email address to identify you.
Please type:
    1 to set up a new account (first-time users);
    2 to log into an existing account (returning users).
Your choice (1 or 2):

ここで注目すべきは最後の、

Your choice (1 or 2):

という一行。

これが出てきたら「2」を入力ししたいわけだから、ワイルドカードを使ってこの行を特定するには、「*choice*:」とすればいい。

ここで行う「*choice*: が出てきたら"2"を入力する」というのをexpect的に書くと

expect "*choice*:" { send "$NO"\n}

こうなる。

$NOには"2"が入っているはずだから2が入力される。最後の"\n"はエンターの意味。

そして「2」を入力すると、

Your choice (1 or 2): 2
Email address:

とすぐにメールアドレスを聞いてくるので、「foo@bar.com」と入力してやればいい。

メールアドレスが登録済だと認証されて解析するデータのダウンロードが始まる。

こんな感じ。

Email address: foo@bar.com
Logged in as FooBar (foo@bar.com)
Number of work units processed: ***
Total CPU time:****
Found data file: no. Found result header file: no.
Getting data - connecting to server.
Receiving data: 10K
長いので省略
Receiving data: 340K
All data received.
Scanning data file
省略。。。
Beginning analysis...
        (This is the last message displayed while the client works.
        To see progress messages between now and completion of
        processing, operate the client with the -verbose option.
        You can also see the progress of the client by looking at
        the 'prog=' line in the state.sah file.

ずらずらっと字が流れる。自分もsetiに詳しいわけじゃなくて聞いたことを実行してるだけなので、聞いたところによるとここまできたら「Ctrl+C」を押して強制的に抜けるしかないらしい。

なのでそれをexpect的に書くと。

expect "*file." {send exit}

となる。ここでポイントなのはターミナルでいう「Ctrl+C」っていうのはシェルで書くと「send exit」と表記するというところ。

実行

ここまでくれば、もうすでにメールアドレスに入力をし終わって解析するデータのダウンロードも終わり。あとは実行するのみ。

実行はspawn内でする必要はないため「"」で閉じてから、その後に

./setiathome

とすれば解析がはじまる。

*1:これは自分の場合であって他の人は違うかもしれない.

*2:「-c」の意味は忘れた.

*3expectからみれば出力か?