other versions
EXPECT(1) | General Commands Manual | EXPECT(1) |
名前¶
expect - 対話的なプログラムとのやりとりを自動化するプログラム, バージョン 5書式¶
expect [ -dDinN ] [ -c cmds ] [ -[f|b] ] cmdfile ] [ args ]イントロダクション¶
Expect は、スクリプトの指示に従って、対話的なプログラムと"会話"するプログラムである。 以下のスクリプトに示すように、 Expect には、対話プログラムからの期待されうる入力とそれに対する正しい応答を 教えておく。インタプリタは分岐処理と高度な制御構造を提供し、 対話プログラムへの指示を行なう。 さらに、必要な時にスクリプトから制御を奪って直接人間が指示を行ない、 その後、制御をスクリプトへ戻すことができる。- •
- 電話代を払わずにログインできるようにコンピュータからあなたに電話を掛け直させる。
- •
- ゲーム(例えば rogue)を始める時に、最適なパラメタがもらえなかった場合 最適なパラメタがもらえるまで何度でもリスタートを行ない、その後制御を人間に移す。
- •
- fsckを走らせた時に現れる質問に、前もって決めておいた方針に従って、 "yes", "no", "手入力"を切替えて、返答する。
- •
- 他のネットワークや BBS(例えばMCI Mail, CompuServe)に接続した時に 自動的にメールの取り込み、発信を行なう。
- •
- 環境変数、カレントディレクトリ、その他の情報を、rlogin, telnet, tip, su, chgrp などを行なった先へ持っていく。
用法¶
Expect は、 cmdfile を読み込み、実行するコマンドのリストを得る。 Expect は、#! 表記をサポートする OS で、先頭行に#!/usr/local/bin/expect -f
#!/usr/local/bin/expect --
send_user "$argv0 [lrange $argv 0 2]\n"
コマンド¶
Expect は、 Tcl (Tool Command Language)を使用している。 Tcl は、制御フロー(例えば if, for, break)、式評価、および、 再帰やプロシジャ定義等他のいくつかの機能を提供する。 ここで使われているのに定義がないコマンド(例えば、 set, if, exec) は、Tcl コマンドである。(tcl(3)を参照)。 Expect は、以下に記述する追加コマンドをサポートする。 記述がない場合は、そのコマンドは空文字列を返す。 コマンドはアルファベットの列なのですぐにわかると思うが、 新しいユーザーは、 spawn, send, expect, interact, が、この順で並んでいるところを読み始めた方が理解しやすいと 気がつくかも知れない。- close [-slave] [-onexec 0|1] [-i spawn_id]
- カレントプロセスへのコネクションをクローズする。
ほとんどの対話型プログラムが標準入力の
EOF を検出し exit する。
それゆえ、 close
はそのプロセスを kill
するのにも通常充分である。
-i
フラグを指示すると、続く
spawn_id
を持つプロセスをクローズする。
- debug [[-now] 0|1]
- は、Tcl
デバッガを制御する。デバッガにより、ステップ実行、ブレークポイントの
設定などが行なえる。
- disconnect
- fork されたプロセスを端末から切り離す。バックグラウンドで動作は続く。 プロセスは可能であれば自分自身のプロセスグループを与える。 標準入出力は、/dev/null にリダイレクトされる。
- 以下の断片は、
disconnect
を使って、バックグラウンドでスクリプトの実行を続ける。
if {[fork]!=0} exit disconnect . . .
以下のスクリプトは、パスワードを読んで、一時間毎にパスワードを要求する プログラムを実行する。スクリプトはパスワードを読み込んでいるので、 タイプするのは一回だけで済む。 (パスワードのエコーを避ける方法については、 stty コマンドを参照)send_user "password?\ " expect_user -re "(.*)\n" for {} 1 {} { if {[fork]!=0} {sleep 3600;continue} disconnect spawn priv_prog expect Password: send "$expect_out(1,string)\r" . . . exit }
シェルの非同期実行(&)時に disconnect を用いる利点は、 Expect が disconnect の前に端末情報を保存しておいて、後で新しい pty にそのパラメタを 適用できる点にある。 & を使っていて Expect が制御を受けとって disconnect されてしまうと、端末情報を読み込むことはできない。
- exit [-opts] [status]
- Expect を exit
させるか、そのための準備を行なう。
- exp_continue [-continue_timer]
- exp_continue コマンドは expect 自身に待っていた値が来なかった時のように、expect の実行を続ける。 デフォルトでは exp_continue は時間切れタイマーをリセットする。 -continue_timer フラグはタイマーを再実行しないようにする。 (より詳細な情報は expect を参照のこと。)
- exp_internal [-f file] value
- value がゼロでなければ、以降のコマンドの診断情報を Expect 内部の stderr に送るようになる。 value に0を指定するとこの出力は止まる。この診断情報には、受けとった すべての文字と、現在の出力とパターンをマッチさせる全試行が 含まれる。
- file
オプションを指定すると、すべての通常および診断出力がそのファイルに
出力される。( value
の値とは無関係に)。すでにオープンされている診断出力ファイルは、
すべてクローズされる。
- exp_open [args] [-i spawn_id]
- 元の spawn id
に結びつけられたファイル
ID を返す。
そのファイル ID は、Tcl
の open
コマンドでオープンした時と同様に扱える。
(spawn id
は、もう使われるべきでない。
wait
も実行すべきではない。)
- exp_pid [-i spawn_id]
- 現在の spawn されたプロセスのプロセス ID を返す。 -i フラグを指示すると、与えられた spawn id に対するプロセスの ID を返す。
- exp_send
- send のエイリアス。
- exp_send_error
- send_error のエイリアス。
- exp_send_log
- send_log のエイリアス。
- exp_send_tty
- send_tty のエイリアス。
- exp_send_user
- send_user のエイリアス。
- exp_version [[-exit] version]
- は、スクリプトが現バージョンのExpectで動くことを確かめる時に役に立つ。
- 引数がなければ、 Expect の現在のバージョンを返す。このバージョンはあなたのスクリプト内で 設定しても良い。あなたが最近のバージョンに入った機能を使わないの であれば、もっと前のバージョンを指定することができる。
- バージョンはドットで区切られた 3 つの番号である。 最初の番号は、メジャー番号である。 違うメジャー番号の Expect 用に書いたスクリプトは、まず動かない。 exp_version は、メジャー番号がマッチしないとエラーを返す。
- 2 番めの番号はマイナー番号である。 使っている Expect よりマイナー番号がより大きい Expect 向けのスクリプトは、 新機能の使用未使用によるが、動かないかも知れない。 exp_version はメジャー番号がマッチしてもマイナー番号が使っている Expect のバージョンより大きいとエラーを返す。
- 3番めの番号は、バージョン比較には使われない。 しかし、文書の更新やプログラムの最適化が行なわれて、 Expect のディストリビューションが更新されると、番号が増えていく。 新しいマイナーバージョンが設定される度に、0 にリセットされる。
- -exit フラグをつけると、バージョンが合わなかった時に Expect はエラーを表示し exit する。
- expect [[-opts] pat1 body1] ... [-opts] patn [bodyn]
- は、spawn されたプロセスの出力がパターンのどれかにマッチするか、 指定された時間が経過するか、enf-of-file を見つけるか、のいずれかが 成立するまでウェイトする。 最後の body が空なら、それは省略できる。
- 一番最後に実行された expect_before コマンドのパターンが、どのパターンより先にチェックされる。 一番最後に実行された expect_after コマンドのパターンが、どのパターンより後にチェックされる。
- expect 全体への引数が 1 行に収まらなかった場合は、 引数を"ブレース"することで、各行の終りにバックスラッシュをつけるのを 避けることができる。この場合、ブレースしたにもかかわらず通常の Tcl 展開が 発生する。
- もし、パターンがキーワード eof であれば、end-of-file 発見時に処理が実行される。 もし、パターンがキーワード timeout であれば、タイムアウトが発生した時に処理が実行される。 timeout キーワードが使われなかった場合、タイムアウト時にはなにもしない。 デフォルトタイムアウトは 10 秒である。設定することもできる。 例えば 30 秒と設定したければ、"set timeout 30"を実行すること。 タイムアウトさせないためには、値 -1 を設定する。 もし、パターンがキーワード default であれば、タイムアウトか end-of-file のいずれかで処理が実行される。
- パターンにマッチすれば、処理は実行される。 expect は、行なった処理(関連するブレース内の処理)の結果を返す。 (パターンにマッチしなかった時は、空文字列を返す。) 複数のパターンにマッチした場合、最初にマッチしたパターンに対応する処理が 実行される。
- 対話型プログラムからの新しい出力が Expect に届くたびに、リストされている順に パターンとの比較が行なわれる。それゆえ、マッチすべきものがないことを 確認するために、プロンプトのように来ることがわかっているパターンを用意する ことができる。 プロンプトがない場合には、(あなたが手で打つ時に判断しているように) timeout を用いなければならない。
- パターンは 3
通りに書ける。デフォルトは、Tcl
の string match
コマンドの書式である。(このパターンはグロブで参照される
C-shell の正規表現に
似ている。) -gl
フラグは、他のマッチからパターンを保護するのに使う。
"-"で始まるパターンは、この方法で保護すべきである。
("-"で始まる文字列は将来の拡張で、オプションとして使われるかも知れないから)
- 例えば、以下の断片はログインの成功を監視する。
(abort
はスクリプトのどこか他の場所で定義されていると仮定している。
注意すること。)
expect { busy {puts busy\n ; exp_continue} failed abort "invalid password" abort timeout abort connected }
4番めのパターンにはスペースが含まれているのでクオートが必要である。 アクションとパターンを分離するセパレータでないことを指示する必要がある。 (3番めと4番めの)ように同じアクションを持つリクエストも並べて書く必要が ある。これは、正規表現パターンを用いることで回避できる(下記参照)。 グロブスタイルパターンについてもっと情報が欲しければ、Tcl のマニュアルを 読むこと。
- 正規表現パターンは、Tcl
の regexp ("regular
expression"の短縮)コマンドで定義される文法に従う。
regexpパターンは、 -re
フラグで始める。
前の例を、regexp
で書き直すと、こうなる。:
expect { busy {puts busy\n ; exp_continue} -re "failed|invalid password" abort timeout abort connected }
どちらのパターンのタイプも、"固定されていない"。どういう意味かというと、 文字列全体にマッチする必要はなくて、文字列のどこでもマッチすれば 良いということである。^ が先頭にマッチする。 $ が末尾にマッチする。 文字列の末尾にマッチさせなければ、spawn されたプロセスからエコーされた 文字列の途中で切り上げてレスポンスを返せることに注意すること。 正しく処理が実行されていても、出力は不自然に見える可能性がある。 それで、文字列の終りの文字を正確に記述できるなら、$ を使うことを勧める。
- -nocase フラグは、小文字が含まれている場合に大文字に変換してからマッチさせる。 パターンには影響しない。
- 出力を読んでいて、2000
バイトを超えてしまったデータは"忘れられる"。
この動作は、 match_max
関数で変更できる。
(極端に大きな値はパターンマッチの性能を低下させることに注意すること。)
patlist に full_buffer
を指定すると、 match_max
バイト以上のデータを受けてパターンマッチしなかったときに、処理が実行される。
full_buffer
キーワードの有無に関わらず、忘れられたデータは
expect_out(buffer)
に保存される。
expect "cd"
で受けると、以下の文を実行したのと同じ結果となる。set expect_out(0,string) cd set expect_out(buffer) abcd
この時、"efgh\n"は出力バッファに残る。 プロセスが"abbbcabkkkka\n"を出力し、以下の形:expect -indices -re "b(b*).*(k+)"
で受けると、以下の文を実行したのと同じ結果になる。set expect_out(0,start) 1 set expect_out(0,end) 10 set expect_out(0,string) bbbcabkkkk set expect_out(1,start) 2 set expect_out(1,end) 3 set expect_out(1,string) bb set expect_out(2,start) 10 set expect_out(2,end) 10 set expect_out(2,string) k set expect_out(buffer) abbbcabkkkk
この時、"a\n"は出力バッファに残る。 パターン"*" (と -re ".*")は、プロセスからのデータがさらに来ない限り、 出力バッファをフラッシュしない。
- 通常、マッチした出力は
Expect
の内部バッファから、切り捨てらる。
この動作は、 -notransfer
フラグで抑止することができる。このフラグは、スクリプトを試している時に
役に立つ(そして、"-not"と略記しても良い)。
expect { -i $proc2 busy {puts busy\n ; exp_continue} -re "failed|invalid password" abort timeout abort connected }
大域変数 any_spawn_id の値は、 今の expect コマンド内で -i フラグを指示した spawn_id の全てにマッチさせるために使われる。 -i フラグをパターンなしで指定すると(すなわち、別の -i が直後に続くと)、 any_spawn_id で指定された、同じ expect コマンド内の他のパターンに対して、有効になる。
- ループを書いたり、expect
コマンドを繰り返すことを避ける時に便利である。
以下の例はログインを自動化するコードの断片である。
exp_continue
によって、(再びプロンプトを探すための)2
つめの expect
コマンドを書かなくて済んでいる。
expect { Password: { stty -echo send_user "password (for $user) on $host: " expect_user -re "(.*)\n" send_user "\n" send "$expect_out(1,string)\r" stty echo exp_continue } incorrect { send_user "invalid password or account\n" exit } timeout { send_user "connection to $host timed out\n" exit } eof { send_user \ "connection to host failed: $expect_out(buffer)" exit } -re $prompt }
例えば、以下の断片は既に自動化されているユーザーガイドへのやりとりを 補助する。 この場合、端末は raw モードになる。 ユーザーが'+'を押すと変数がインクリメントされる。 "p"が押されると、プロセスへ復帰情報が送られる。 おそらくは同じように"i"が押されると、スクリプトから制御を奪い、 ユーザーからの制御が行なえる。 どの場合も exp_continue コマンドが、今の expect に、処理を行なわせた後再びパターンマッチさせている。stty raw -echo expect_after { -i $user_spawn_id "p" {send "\r\r\r"; exp_continue} "+" {incr foo; exp_continue} "i" {interact; exp_continue} "quit" exit }
- デフォルトでは、 exp_continue は、タイムアウトタイマーをリセットする。 タイマを再開させるには、 exp_continue コマンドに -continue_timer フラグをつける。
- expect_after [expect_args]
- は、 expect_before と同様の動きをするが、 expect と expect_after の両方にマッチした場合、 expect のパターンが使用される点が異なる。 より詳しい情報は、 expect_before コマンドの項を参照のこと。
- expect_background [expect_args]
- は、 expect
と同じ引数をとるが、その場で復帰する。
パターンは新しいデータが届くたびにチェックされる。
パターン timeout と default
は、 expect_background
には、意味がないし、無視される。
expect と同様に、
expect_background コマンドは
expect_before や expect_after
パターンを使える。
- expect_before [expect_args]
- は expect
と同じ引数をとるが、その場で復帰する。
もっとも最近、同じ
spawn id に対して expect_before
で使われたパターン・アクションのペアが、続く
expect
コマンドに対して使用される。
パターンがマッチすると、
expect
コマンドにマッチした時と同じように動作する。
処理は、その expect
のコンテキストで行なわれる。
expect_before と expect
の両方のパターンにマッチした場合、
expect_before
のパターンが使われる。
expect_before -info -i $proc
たった一つの spawn id 指定だけが許される。-indirect フラグで、直接 spawn id を抑止し、間接的な指定から得られるidを指示する。
- expect_tty [expect_args]
- は、 expect と似た動きをするが、文字列を /dev/tty (すなわち、ユーザーからのキー入力) から読み込む。 デフォルトでは、cooked mode で読み込まれるので、 行はリターンで終らなければならない。そうしないと expect が読めない。この動きは、 stty を使って変えられる。 (下の stty コマンドを参照)
- expect_user [expect_args]
- は expect と似た動きをするが、文字列を stdin(すなわち、ユーザーからのキー入力) から読み込む。 デフォルトでは、cooked mode で読み込まれるので、 行はリターンで終らなければならない。そうしないと expect が読めない。この動きは、 stty を使って変えられる。 (下の stty コマンドを参照)
- fork
- は、新しいプロセスを作る。この新しいプロセスは、現在の Expect プロセスの正確なコピーである。 成功すると fork は 新しい(子)プロセスに 0 を返し、親プロセスに 子プロセスのプロセスIDを 返す。 失敗する(スワップ、メモリなどのリソース不足か?)と、 fork は、親プロセスに -1 を返す。新しい子プロセスは作成されない。
- フォークされたプロセスは、 exit コマンドで ext できる。元のプロセスと同様である。 フォークされたプロセスはログファイルを作っても良い。多くのプロセスで デバッグもログもできなければ、結果、混乱するだけである。
- pty のインプリメンテーションの中には、複数の読み手と書き手が一瞬でもあれば、 混乱するものがある。それで、プロセスを spawn する前には fork しておくのが一番安全である。
- interact [string1 body1] ... [stringn [bodyn]]
- は、現プロセスの制御をユーザーに渡す。結果、 現プロセスに送られたキーストロークと現プロセスの標準出力と標準エラー出力が 復帰する。
- string と body の組が、引数として指示できる。(デフォルトでは、 文字列は現プロセスには送られない) 最後の body がないと、 interpreter コマンドが実行される。
- interact コマンド全体への引数が一行に収まらない場合、"brace"することで各行の終りに バックスラッシュを入れるのを避けることができる。この場合、Tcl の展開は ブレースしてあっても起こる。
- 例えば、以下のコマンドは続く
string body
の組と対話する。 : ^Z
が押されると Expect
はサスペンドする。 (
-reset
フラグは、端末モードを復旧させる。)
^A
が押されると、ユーザーには"you
typed a control-A"が返る。
$ が押されると、ユーザーには日付が返る。 ^C が押されると、 Expect は、exit する。 "foo"が入力されると、ユーザーに "bar" が返る。 ~~ が押されると、 Expect インタプリタは、対話モードになる。set CTRLZ \032 interact { -reset $CTRLZ {exec kill -STOP [pid]} \001 {send_user "you typed a control-A\n"; send "\001" } $ {send_user "The date is [exec date]."} \003 exit foo {send_user "bar"} ~~ }
- string と body の組で、string が引数として並べられた順に比較される。 部分的にマッチした文字列は、残りが到着するまで送られて来ない。 何文字かさらに打ち込まれて、マッチが可能になると、今のマッチを判断する ためにだけ使われて他のマッチを始めることはしない。それゆえ、部分的に マッチしている文字列のマッチが完了するのは遅れることがある。 部分的にはマッチするが最終的にはマッチしない文字列の場合などである。
- デフォルトでは、ワイルドカードを含まないマッチは、exactとなる。
( expect
コマンドがデフォルトでグロブスタイルのパターンを用いるのとは対照的に。)
-ex
フラグは、パターンをプロテクトするのに使える。
interact
フラグがそうするように。
パターンが"-"で始まる場合、この方法で保護できる。
("-"で始まる文字列は全て将来のオプションとして予約されている。)
interact -input $user_spawn_id timeout 3600 return -output \ $spawn_id
- interact の間 raw モードが使用されるので、全ての文字が現プロセスに渡される。 現プロセスがジョブコントロールシグナルを捕まえなければ、 ストップシグナル(デフォルト^Z)で停止する。再スタートするには、 制御シグナルを送る。("kill -CONT <pid>"とか打って)。 本当に SIGSTOP をプロセスに送りたいなら、csh を spawn してその上で プロセスを起動すること。 そうでなくて、 Expect そのものに SIGSTOP を送りたいなら、インタプリタを呼び出して (普通はエスケープ文字)、その後 ^Z を打つこと。
- string bodyのペアは、インタプリタに入ってコマンドを対話的に実行するのを 避けることを簡単に書くのに使われる。 前の端末モードが、その body を実行する間使用される。
- 実行速度を上げるには、デフォルトでアクションが raw モードで動くように する。 -reset フラグは、端末の持っているモードをリセットする。そうしなければ、 その前に行なった interact コマンドの端末モード(cooked モードとか)が保持される。 モードが切り替わった時に、それまで打っていた文字が消えてしまうことが あるので注意すること。(システムによっては、そういう不幸な仕様をした 端末ドライバが動いている。) -reset を使うのは、アクションが cooked モードでしか動かない場合だけである。
- -echo フラグは、一文字づつパターンにマッチする文字を返す。これは、 ユーザーが打つ文字に部分的にマッチしなければならない場合に有効である。
- パターンはエコーされたがマッチには失敗した場合、文字列は、spawn
された
プロセスに送られる。それから、spawn
されたプロセスが文字列を表示し、
ユーザーは文字列を二度見る。
-echo
は、ユーザーがパターンを完成させてくれそうもない場合にだけ有効であろう。
例えば、以下は
rftp(リカーシブ ftp
スクリプト)からの抜粋だが、ユーザーが
~g, ~p, ~l
を打つとカレントディレクトリから再帰的(リカーシブ)に
get, put, list する。通常の ftp
ではこれらの操作ができない。間違って
~ を 打つか、~
の後を間違えた場合、その文字列を無視するようになっている。
interact { -echo ~g {getcurdirectory 1} -echo ~l {getcurdirectory 0} -echo ~p {putcurdirectory} }
-nobuffer フラグは、文字が読まれる度に、その文字をマッチへ送る。proc lognumber {} { interact -nobuffer -re "(.*)\r" return puts $log "[exec date]: dialed $interact_out(1,string)" } interact -nobuffer "atd" lognumber
- interact の間、前に使った log_user は無視される。特に、 interact は、その出力を記録される(標準出力に送られる)。 というのは、ユーザーはエコーバックのない状態でキーを打ちたくはない だろうと考えるからである。
- -o フラグは、現プロセスの出力に key body ペアの key を結びつける。 こんな場合に便利である。例えば、telnet セッション中に望まない文字を 送ってくるホストを扱う場合である。
- デフォルトでは、 interact は、ユーザーが Expect プロセス自身の標準入力に書き込み、標準出力を見ていると思っている。 -u フラグ("user"のu)は interact に、引数で付けられた名前(spawned id である)のプロセスをユーザーとして 扱う。
- これにより、変なループなしに2つの無関係なプロセスを結合させることが できる。デバッグする時の助けとして、Expect は常に診断結果を stderr へ送る。(ある種のログとデバッグ情報は stdout に送られる)。 同じ理由で、 interpreter コマンドは、stdin からデータを読む。
- 例えば、以下の断片はログインプロセスを作る。そして、(表示されない)
ユーザーにダイアルし、両方の接続を行なう。
もちろん、loginをどんなプロセスに変えても良い。例えば、シェルなら、ア
カウントとパスワードを与えなくてもユーザーが起動できる。
spawn login set login $spawn_id spawn tip modem # dial back out to user # connect user to login interact -u $login
複数のプロセスへの出力を行なうため、 -output フラグを前につけた各 spawn id のセットがリストされる。 出力 spawn id の組への入力は、 -input フラグによって決定される。 ( -input と -output フラグは両方とも expect コマンドの -i フラグと同じ書式である。( interact 内の any_spawn_id は意味がない点を除く。) 以下のフラグと文字列(あるいはパターン)は全て、別の -input フラグが現れるまで この入力を適用する。 -input が現れなかった場合、 -output は "-input $user_spawn_id -output" を行なう。 ( -input を持たないパターンも同様である。) -input が一つだけ指示されると、$user_spawn_id はその値で置き換わる。 二つめの -input が指示されると、$spawn_id が置き換わる。 以降の -input フラグも指定できる。
- interpreter [args]
- は、ユーザーに Expect と Tcl コマンドのためのプロンプトを表示する。 各コマンドの結果が表示される。
- break や continue は制御構造(すなわち、 for proc )で、通常通りに動く。 しかし、 return は、呼出元への復帰を行なうのに対し、 inter_return は interpreter を、呼出元を復帰させる。たとえば、 "proc foo" は、 interpreter を呼び、 inter_return を実行し proc foo が復帰する。 他のコマンドは interpreter に新しいコマンドのためのプロンプトを表示し続ける。
- デフォルトでは、プロンプトは 2 つの整数を含んでいる。 最初の数は評価スタックの深さ(つまり、何回 Tcl_Eval が呼ばれたか) 2番めの数は、Tcl ヒストリ識別番号である。プロンプトは "prompt1"と呼ばれるプロシジャを定義することで設定できる。 このプロシジャの帰り値が次のプロンプトとなる。 記述に開きクオート、括弧、ブレース、ブラケットがあると、次の行には 第 2 プロンプトが現れる(デフォルトは "+> ")。第 2 プロンプトは "prompt2"と呼ばれるプロシジャを定義することで設定できる。
- interpreter の間は、呼出元が raw モードであったとしても、cooked モードが使われる。
- stdin が閉じられると、 interpreter は -eof フラグが使われていない限り復帰する。 使われている場合は引き続く引数を実行する。
- log_file [args] [[-a] file]
- ファイル名が与えられると、
log_file
は、(現時点からの)セッションのログをそのファイルに採取する。
引数がなければ、
log_file
は記録をやめる。使っていたログファイルはクローズされる。
- log_user -info|0|1
- デフォルトでは、send/expect
ダイアログは標準出力にロギングされる。
(開いていればログファイルにもロギングされる。)
"log_user
0"とすると、標準出力へのロギングが抑止される。
"log_user
1"とすると、復旧する。ログファイルへの記録については
変更はない。
- match_max [-d] [-i spawn_id] [size]
- は、バッファサイズを(バイト単位で)定義する。このバッファは、 expect の内部で使われる。 引数 size がないと、現在のサイズを復帰する。
- -d フラグを指示すると、デフォルトサイズが設定される。(初期状態の デフォルト値は 2000。) -i フラグを指示すると、名前つき spawn id に対してサイズが設定される。 指定しなければ、カレントプロセスに対して設定される。
- overlay [-# spawn_id] [-# spawn_id] [...] program [args]
- は、 program args を現在の Expect プログラム上で実行する。現在の Expect プログラムは終了する。 ただのハイフンが引数に指定されると、コマンド名の前にハイフンをつけて ログインシェルとして扱う。 全てのクローズ中の spawn_id は、引数に使われた文字列を待つ。
- Spawn_id
は、新しいプログラムに継承させるためのファイル
ID に
マップされる。例えば、以下の行はチェスを行ない、chess
master
という現プロセスに制御させる。
overlay -0 $spawn_id -1 $spawn_id -2 $spawn_id chess
これは、 "interact -u" とするよりも効果的である。しかし、 Expect プロセスが制御していないのでプログラム能力が犠牲となる。
- 制御されない端末ができてしまうことに注意すること。それで、 disconnect するか標準入力をリマップするとジョブ制御プログラム (シェル、ログインなど)が正しく機能しない。
- parity [-d] [-i spawn_id] [value]
- は、spawn idの出力からパリティを保持するか取り除くかを設定する。 value が 0 であれば、パリティは取り除かれる。 それ以外の場合、取り除かれない。 value が指定されない場合、現在の値が復帰する。
- -d フラグは、パリティのデフォルト値を設定する。(イニシャル時のデフォルト値は 1 である。すなわち、パリティが取り除かれる。) -i フラグを指示すると、パリティの値が引数の名前つきの spawn id に対して 設定される。引数がなければ現在のプロセスに対して設定される。
- remove_nulls [-d] [-i spawn_id] [value]
- は、前にパターンマッチしたあるいは expect_out か interact_out に保存されている spawn されたプロセスの出力からヌルを保持するか取り除くかを 設定する。 value が 1 なら、ヌルは取り除かれる。もし、 value が 0 なら、ヌルは取り除かれる。 value がなければ、現在の値が復帰する。
- -d
フラグは、デフォルト値を設定する。(イニシャルのデフォルト値は、
1
である。それゆえ、ヌルは取り除かれる。)
-i
フラグは、名前つきの
spawn id
に対して値を設定する。なければ、
現プロセスに対して設定する。
- send [-flags] string
- string
を現プロセスに送る。
例えば、以下のコマンド:
send "hello world\r"
は、文字 h e l l o <blank> w o r l d <return> を現在のプロセスに 送る。 (Tcl は、printf に似たコマンド ( format と呼ばれる )を持っていて、複雑な文字列を組み立てることができる。)
- 文字は直ちに送られる。ただし、入力にラインバッファのあるプログラムでは、
リターンコードが送られるまで文字が読まれない。リターンコードは、
"\r"と表記する。
set send_human {.1 .3 1 .05 2} send -h "I'm hungry. Let's do lunch."
ハングさせてしまった後は、以下のようにした方が良いだろう。:set send_human {.4 .4 .2 .5 100} send -h "Goodd party lash night!"
send にエラーや修正を埋め込んであっても、 エラーはシミュレートされない点に注意すること。# どのように破るかのヒントをハッカーに与えてしまわないように、 # このシステムでは外部のパスワードに対するプロンプトを提供しない。 # exec が完了するのを 5 秒待て。 spawn telnet very.secure.gov sleep 5 send password\r
exp_send は send のエイリアスである。あなたが Expectk か、Tk 環境で動く Expect の他の変種を 使っている場合、 send は、全く異なった目的のために使われている。 exp_send が、両環境の間での互換性のために提供されている。 似たようなエイリアスが他の Expect の他の send コマンドのために提供されている。
- send_error [-flags] string
- send と似たようなもので、現プロセスでなく stderr に出力される。
- send_log [--] string
- send と似たようなもので、ログファイルだけに string を送る。( log_file を参照。) 引数はログファイルが open されていなければ無視される。
- send_tty [-flags] string
- send と似たようなもので、現プロセスでなく /dev/tty へ出力を送る。
- send_user [-flags] string
- send と似たようなもので、現プロセスでなく標準出力へ出力を送る。
- sleep seconds
- は、与えられた数字の秒数だけスクリプトがスリープする。 seconds は、10進数だけが許される。 (Expectk を使っている場合、Tkのイベントと)割り込みは、Expectが スリープしている間も処理される。
- spawn [args] program [args]
- program args を走らせる新しいプロセスを生成する。その標準入力と標準出力は Expect に結びつけられる。それで、他の Expect コマンドで読んだり書いたりできる。 接続は close によって、あるいは、プロセスそのものがファイル ID の いずれかをクローズした場合、破壊される。
- プロセスは spawn によって始められる。変数 spawn_id には、そのプロセスへの参照を行なう識別子が設定される。 spawn_id によって記述されるプロセスは current process が考慮される。 spawn_id は、読んでも書いても良く、効果的なジョブ制御を提供する。
- user_spawn_id
はユーザーを参照する識別子の入ったグローバル変数である。
例えば、 spawn_id
が、この値に設定された場合、
expect は、 expect_user
のような動きをする。
- tty_spawn_id は、/dev/tty
を参照する識別子の入ったグローバル変数である。
/dev/tty が存在しない(cron, at,
バッチスクリプトの中)場合、
tty_spawn_id
は定義されない。以下のように確認することができる。:
if {[info vars tty_spawn_id]} { # /dev/tty exists } else { # /dev/tty doesn't exist # probably in cron, batch, or at script }
- spawn UNIX プロセス ID を復帰する。spawn されたプロセスがない場合、0 が 復帰する。変数 spawn_out(slave,name) は pty スレーブデバイスの名前に設定される。
- デフォルトでは、 spawn はコマンド名と引数をエコーする。 -noecho フラグで spawn がこうするのを止められる。
- -console
フラグは、コンソールへの出力を起こし、spawn
されたプロセスへの
リダイレクトされる。この機能は未サポートのシステムがある。
- 普通、 spawn
は、実行するのにわずかの時間しかかからない。spawn
に時間をかけたいので
あれば、おそらく割り込まれた
pty
に遭遇するだろう。たくさんのテストが
間違ったプロセスに掛かり合うことを避けることができる。
(割り込まれた pty
につき、10
秒かかる。) -d
オプションをつけて
Expect を走らせると、
Expect
がおかしな状態のたくさんの
pty
に遭遇しているかどうかが表示される。
これらの pty
がつながっているためにプロセスを殺せない場合、リブートするしか
頼れる復旧手段はない。
- strace level
- は、以降の命令を実行する前に表示を行なう。
(Tcl の trace
は、変数のトレースを行なう。)
level
は、トレースへの呼び出しスタックの深さを示す。
例えば、
以下のコマンドは
Expect 最初の 4
レベルの呼び出しをトレースする。
それ以上の深さはトレースしない。
expect -c "strace 4" script.exp
- stty args
- は端末モードを変更する。外部の
stty
コマンドと似たようなものである。
- 以下の例は、一時的なエコー禁止をどうやっておこなうかを示す。
これは、他の自動スクリプトで、その中にパスワードが埋め込まれるのを
防ぐことに使われる。(もっと議論したければ、下の
EXPECT ヒントに ある。)
stty -echo send_user "Password: " expect_user -re "(.*)\n" set password $expect_out(1,string) stty echo
- system args
- は、 args を、sh(1)に入力する。端末からコマンドを叩くのとちょうど同じである。 Expect は、シェルが終るのを待つ。sh からの復帰値は、 exec がその復帰値を扱うのと同じに扱われる。
- exec が、スクリプトに標準入出力をリダイレクトするのと対照的に、 対照的に system は、リダイレクションを行なわない。(他に文字列そのものでリダイレクトを 指示しない限り。) それで、/dev/tty と直接話さなければならないプログラムを 使うことができる。同じ理由で、 system の結果は、ログに記録されない。
- timestamp [args]
- は、タイムスタンプを復帰する。
引数がない場合、復帰するまでの秒数が返る。
%a 略記された曜日の名前 %A 略されない曜日の名前 %b 略記された月の名前 %B 略されない月の名前 %c 次の形式で書かれた時刻: Wed Oct 6 11:45:56 1993 %d 日 (01-31) %H 時 (00-23) %I 時 (01-12) %j 日 (001-366) %m 月 (01-12) %M 分 (00-59) %p am または pm %S 秒 (00-61) %u 日 (1-7, 月曜日が週の最初の日) %U 週 (00-53, 最初の日曜日が第1週の最初の日) %V 週 (01-53, ISO 8601 スタイル) %w 日 (0-6) %W 週 (00-53, 最初の月曜日が第1週の最初の日) %x date-time as in: Wed Oct 6 1993 %X time as in: 23:59:59 %y year (00-99) %Y year as in: 1993 %Z timezone (or nothing if not determinable) %% a bare percent sign
この他の % 指定は定義されていない。他の文字は変更されない。 C ロカールだけがサポートされる。
- trap [[command] signals]
- を実行すると、以降指定された
signal
を受けとると指定された
command を実行する。
このコマンドは、グローバルスコープで実行される。
もし、 command
が指定されなければ、シグナルアクションが復帰する。
command が、文字列 SIG_IGN
であれば、シグナルが無視される。
command が、文字列 SIG_DFL
であれば、シグナルはデフォルトの動きをする。
signals
は、シグナルが1つでも複数のシグナルのリストでも良い。シグナルは、
数字とsignal(3)に記述されている文字列のどちらで指定しても良い。
プレフィクスの"SIG"は、省略しても良い。
trap exit {SIGINT SIGTERM}
-Dフラグを使ってデバッガを起動するなら、SIGINT が再定義されてから対話型 デバッガが起動される。これは以下の trap によって起こる。trap {exp_debug 1} SIGINT
デバッガのトラップは、環境変数 EXPECT_DEBUG_INIT を設定して、新しく trap を起動することで変更できる。if ![exp_debug] {trap mystuff SIGINT}
代わりに、別のシグナルを使ってデバッガに割り込みをかけることができる。
- wait [args]
- は、spawn されたプロセス(あるいは、名前つきのプロセスがなければ現在のプロセス) が終了するのを待つ。
- wait は、通常 4
つの整数のリストを帰す。
最初の整数は、終了を待ち構えているプロセスの
pid である。 2
つめの整数は、関連する
spawn id である。 3
つめの整数は、オペレーティングシステムエラーがあれば
-1、
そうでなければ、0
である。 3
つめの整数が 0
であれば、4
つめの整数はspawnされたプロセスからのリターン
コードである。3
つめの整数が -1
であれば、4
つめの整数はオペレーティングシステム
によって設定された
errno
の値である。グローバル変数
errorCode も設定される。
- -i
フラグによって、wait
を行なう名前付き
spawn_id(プロセス ID
ではなく)を
指定する。SIGCHLD
ハンドラの内部では、spawn
ID -1
を指定することで、
spawn
されたプロセスのいずれかを
wait できる。
ライブラリ¶
Expect は、スクリプトのための二つのビルトインライブラリを自動的に理解する。 それらは変数 exp_library と変数 exp_exec_library に設定されたディレクトリ名と して定義される。これらのディレクトリには、他のスクリプトによって使える ユーティリティファイルが入っている。整形印刷¶
Expect スクリプトをきれいに印刷するための vgrind の定義がある。 Expect ディストリビューションと一緒に配布されている vgrind 定義が正しく インストールされていると仮定して、こうすれば使える。vgrind -lexpect file
例¶
マニュアルページによる記述では、あらゆるものをどう組み合わせるのかと いうことが明白ではない。私としては、 Expect ディストリビューションの example ディレクトリにある例を読んで試してみて欲しいと思う。 いくつかは本物のプログラムである。それ以外は特定のテクニックの単純な解説、 あと、もちろん、単なるクイックハックが少しある。 INSTALL ファイルにはこれらのプログラムの簡単な梗概が書かれている。 Expect の論文も役に立つ(関連項目参照)。いくつかは、初期バージョンの Expect の 文法を使っているが、それとともにある根本的な考えは、なお有効であり、 このマニュアルページより詳細に書かれている。警告¶
拡張は Expect のコマンド名と衝突するかもしれない。例えば、 send は、Tk では全く別の目的で定義されている。 そういう理由で、ほとんどの Expect コマンドは、"exp_XXXX" という 別の記法(エイリアス)もサポートする。 "exp", "inter", "spawn", "timeout" で始まるコマンドと変数は、 エイリアスを持たない。 この環境間の互換性が必要であれば、拡張されたコマンド名を用いること。バグ¶
プログラムに "sex" ("Smart EXec" か "Send-EXpect" の略) という名前を つけるのは実に魅力的だったのだが、センスの良い方(あるいは、 単にピューリタニズム)が優先された。set env(TERM) vt100
set env(SHELL) /bin/sh set env(HOME) /usr/local/bin
spawn date sleep 20 expectのような Expect プログラムは失敗する。失敗しないように非対話的なプログラムでは spawn せずに exec すること。こういう状況は考えられるが、実際には私はまだその状態に 陥ったことがない。つまり、この原因で対話プログラムの最後の出力を 取りこぼすという状態になったことがない。
send "speed 9600\r"; sleep 1 expect { timeout {send "\r"; exp_continue} $prompt }
EXPECT ヒント¶
Expect について、直観的でない点が少しある。 このセクションではそういったことの指摘とそれに対する示唆を試みる。set prompt "(%|#|\\$) $" ;# default prompt catch {set prompt $env(EXPECT_PROMPT)} expect -re $prompt私としては、見えると思っているものの終りの部分を含んだ expect パターンを書くように勧める。そうすれば、全体を見る前に応答を返してしまう ことを避けることができる。さらに、全体が見える前に答えることもできるが その文字は質問に混ざって echo される。言い替えれば、会話は正常だが見た目は 混ざって見える。
2751 (-rwxr-s--x) で、同じグループの所有で作成する。 こうすると、シェルスクリプトはだれからも実行でき(かつ、読め)る。 実行すると、それは Expect スクリプトを実行する。
関連項目¶
Tcl(3), libexpect(3)著者¶
Don Libes, National Institute of Standards and Technology謝辞¶
Tclを生み出した John Ousterhout と、インスピレーションを与えてくれた Scott Paisley に感謝する。 Expect のオートコンフィギュレーションコードについて、 Rob Savoye に感謝する。29 December 1994 |