expect 指令依據腳本和其它程式互動,預期 (expect) 對方的輸出而給對應的回應。
expect 是擴充 tcl 的直譯式語言,提供 branching 和高階控制架構來引導對話。需要時,使用者可以取得控制直接互動,後來再將控制權交還給 script。expect 實際上可以同時連線多個程式。
構想來自普遍在 uucp、kermit 和其它數據機控制程式的 send/expect sequences.
指令格式
expect [ -dDinN ] [ -c cmds ] [ [ -[f|b] ] cmdfile ] [ args ]
讀 cmdfile 取得要執行指令,或在可執行腳本首行放
#!/usr/bin/expect -f
來隱含 invoke。
- cmdfile:
- -f cmdfile:prefaces a file from which to read commands from. 只用在可執行腳本首行的 #!,so that other arguments may be supplied on the command line.
- -b cmdfile:batch 模式,一行一行讀取 cmdfile,例如 stdin 就是用這種方式讀取。預設 cmdfile 是一次讀到記憶體來執行。Note that stdio-buffering may still take place however this shouldn't cause problems when reading from a fifo or stdin.
- -b - 或 -:cmdfile 檔名用「-」使用 stdin。
- -c cmds:預先執行的指令。The command should be quoted to prevent being broken up by the shell. 可有多個 -c 按照出現順序執行,或者多個指令用分號隔開使用單一 -c。
- -d:啟用 some diagnostic 輸出,主要回報內部 activity of commands such as expect and interact。相當於「exp_internal 1」at the beginning of an Expect script, plus the version of Expect is printed. (The strace command is useful for tracing statements, and the trace command is useful for tracing variable assignments.)
- -D:啟用 an interactive debugger. An integer value should follow. The debugger will take control before the next Tcl procedure if the value is non-zero or if a ^C is pressed (or a breakpoint is hit, or other appropriate debugger command appears in the script). See the README file or SEE ALSO (below) for more information on the debugger.
- -i:causes Expect to interactively prompt for commands instead of reading them from a file. Prompting is terminated via the exit command or upon EOF. See interpreter (below) for more information. -i is assumed if neither a command file nor -c is used.
- --:表示給 expect 的選項結束,之後的引數直接 pass 給腳本,包括「-」開頭的引數。適合用在腳本的 #! 行。For example, the following will leave the original arguments (including the script name) in the variable argv.
#!/usr/bin/expect --
Note that the usual getopt(3) and execve(2) conventions must be observed when adding arguments to the #! line.
- -N:The file $exp_library/expect.rc is sourced automatically if present, unless the -N flag is used. (When using Expectk, this option is specified as -NORC.) Immediately after this, the file ~/.expect.rc is sourced automatically, unless the -n flag is used. If the environment variable DOTDIR is defined, it is treated as a directory and .expect.rc is read from there. This sourcing occurs only after executing any -c flags.
- -v:印版號後離開。
Optional args are constructed into a list and stored in the variable
named argv. argc is initialized to the length of argv.
argv0 is defined to be the name of the script (or binary if no script
is used). For example, the following prints out the name of the script
and the first three arguments:
send_user "$argv0 [lrange $argv 0 2]\n"
指令
expect 使用 Tcl (Tool Command Language) 提供流程控制 (例如 if, for, break)、expression evaluation、和幾個其它 features such as recursion, procedure definition 等。這裡沒定義的指令是 Tcl 指令 (如 set, if, exec),見 tcl(3)。expect 額外支援的指令如下,除非特別 specified,指令回 empty string。
指令按照字母排序,但新使用者可能要先看 spawn、send、expect、和 interact 較容易。
接下來,用「Expect」表示程式 (Linux 下的指令),「expect」表示 Expect 程式裡的 expect 指令。
- close [-slave] [-onexec 0|1] [-i spawn_id]
-
停止連線到程式,大部分程式偵測到 stdin EOF 後也會自動結束。expect 和 interact 都會偵測連線的程式結束而隱含 close,但如果用「exec kill $pid」來停止 process,需要明確 close。
-i spawn_id:停止連線到指定的 spawn_id。
-onexec:determines whether the spawn id will be closed
in any new spawned processes or if the process is overlayed. To
leave a spawn id open, use the value 0. A non-zero integer value
will force the spawn closed (the default) in any new processes.-slave:closes the slave associated with the spawn id.
(See "spawn -pty".) When the connection is closed, the slave is
automatically closed as well if still open.No matter whether the connection is closed implicitly or explicitly, you should call wait to clear up the corresponding kernel process slot. close does not call wait since there is no guarantee that closing a process connection will cause it to exit.
- debug [[-now] 0|1]
-
控制 Tcl debugger 來 step through statements、設 breakpoints 等。
no arguments:看 debugger 是否執行中,回 0 表示執行中,1 不在執行中。
1:啟動 debugger。(下個 Tcl statement 開始)
-now 1:馬上啟動 debugger。(在本身 debug 指令中間就啟動)
0:停止 debugger。
The debug command does not change any traps. 比較 Expect 的 -D 參數。
- disconnect
-
中斷和親 process 的連繫,繼續在背景執行,會有自己的 process group (可能的話),標準 I/O 導到 /dev/null。
下列 script 預先讀取 priv_prog 需要的 password,然後每小時背景執行 priv_prog。(見 stty 如何關閉 password echoing。)
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 的好處是在和親 process 的斷線前可以儲存參數,然後用在新建立的 ptys。如果用 shell 的 asynchronous process feature (&),Expect 沒有機會讀取 the terminal's parameters since the terminal is already disconnected by the time Expect receives control.
- exit [-opts] [status]
causes Expect to exit or otherwise prepare to do so.
-onexit:causes the next argument to be used as an exit handler. Without an argument, the current exit handler is returned.
-noexit:causes Expect to prepare to exit but stop short of actually returning control to the operating system. The user-defined exit handler is run as well as Expect's own internal handlers. No further Expect commands should be executed. This is useful if you are running Expect with other Tcl extensions. The current interpreter (and main window if in the Tk environment) remain so that other Tcl extensions can clean up. If Expect's exit is called again (however this might occur), the handlers are not rerun.
Upon exiting, all connections to spawned processes are closed. Closure will be detected as an EOF by spawned processes. exit takes no other actions beyond what the normal _exit(2) procedure does. Thus, spawned processes that do not check for EOF may continue to run. (A variety of conditions are important to determining, for example, what signals a spawned process will be sent, but these are system-dependent, typically documented under exit(3).) Spawned processes that continue to run will be inherited by init.
status (or 0 if not specified) is returned as the exit status of Expect. exit is implicitly executed if the end of the script is reached.
- exp_continue [-continue_timer]
The command exp_continue allows expect itself to continue execut‐
ing rather than returning as it normally would. By default
exp_continue resets the timeout timer. The -continue_timer flag
prevents timer from being restarted. (See expect for more infor‐
mation.)exp_internal [-f file] value
causes further commands to send diagnostic information internal
to Expect to stderr if value is non-zero. This output is dis‐
abled if value is 0. The diagnostic information includes every
character received, and every attempt made to match the current
output against the patterns.
If the optional file is supplied, all normal and debugging output
is written to that file (regardless of the value of value). Any
previous diagnostic output file is closed.
The -info flag causes exp_internal to return a description of the
most recent non-info arguments given.exp_open [args] [-i spawn_id]
returns a Tcl file identifier that corresponds to the original
spawn id. The file identifier can then be used as if it were
opened by Tcl's open command. (The spawn id should no longer be
used. A wait should not be executed.
The -leaveopen flag leaves the spawn id open for access through
Expect commands. A wait must be executed on the spawn id.exp_pid [-i spawn_id]
returns the process id corresponding to the currently spawned
process. If the -i flag is used, the pid returned corresponds to
that of the given spawn id.exp_send
is an alias for send.exp_send_error
is an alias for send_error.exp_send_log
is an alias for send_log.exp_send_tty
is an alias for send_tty.exp_send_user
is an alias for send_user.exp_version [[-exit] version]
is useful for assuring that the script is compatible with the
current version of Expect.
With no arguments, the current version of Expect is returned.
This version may then be encoded in your script. If you actually
know that you are not using features of recent versions, you can
specify an earlier version.
Versions consist of three numbers separated by dots. First is
the major number. Scripts written for versions of Expect with a
different major number will almost certainly not work. exp_ver‐
sion returns an error if the major numbers do not match.
Second is the minor number. Scripts written for a version with a
greater minor number than the current version may depend upon
some new feature and might not run. exp_version returns an error
if the major numbers match, but the script minor number is
greater than that of the running Expect.
Third is a number that plays no part in the version comparison.
However, it is incremented when the Expect software distribution
is changed in any way, such as by additional documentation or op‐
timization. It is reset to 0 upon each new minor version.
With the -exit flag, Expect prints an error and exits if the ver‐
sion is out of date.- expect [[-opts] pat1 body1] ... [-opts] patn [bodyn]
-
等候 spawn 的 process 輸出直到符合其中一個 pattern、EOF、或 timeout。If the final body is empty, it may be omitted.
Patterns from the most recent expect_before command are implicitly used before any other patterns. Patterns from the most recent expect_after command are implicitly used after any other patterns.
If the arguments to the entire expect statement 需要跨多行,可以 "braced" into one 來避免每行以 backslash 結束。the usual Tcl substitutions will occur despite the braces。
如果 pattern 是 keyword eof,the corresponding body is executed upon end-of-file. If a pattern is the keyword timeout, the corresponding body is executed upon timeout. If no timeout keyword is used, an implicit null action is executed upon timeout。預設 timeout 是 10 秒,但 may be set, for example to 30, by the command "set timeout 30". An infinite timeout may be designated by the value -1. If a pattern is the keyword default, the corresponding body is executed upon either timeout or end-of-file.
If a pattern matches, then the corresponding body is executed. expect returns the result of the body (or the empty string if no pattern matched).
Each time new output arrives, it is compared to each pattern in
the order they are listed. Thus, you may test for absence of a
match by making the last pattern something guaranteed to appear,
such as a prompt. In situations where there is no prompt, you
must use timeout (just like you would if you were interacting
manually).Patterns are specified in three ways. 預設用 Tcl 的 string match 指令,(Such patterns are
also similar to C-shell regular expressions usually referred to
as "glob" patterns). The -gl flag may may be used to protect
patterns that might otherwise match expect flags from doing so.
Any pattern beginning with a "-" should be protected this way.
(All strings starting with "-" are reserved for future options.)For example, the following fragment looks for a successful login.
(Note that abort is presumed to be a procedure defined elsewhere
in the script.)
expect {
busy {puts busy\n ; exp_continue}
failed abort
"invalid password" abort
timeout abort
connected
}Quotes are necessary on the fourth pattern since it contains a space, which would otherwise separate the pattern from the action. More information on forming glob-style patterns can be found in the Tcl manual.
Regexp-style patterns follow the syntax defined by Tcl's regexp command. regexp patterns are introduced with the flag -re. The previous example can be rewritten using a regexp as:
expect {
busy {puts busy\n ; exp_continue}
-re "failed|invalid password" abort
timeout abort
connected
}Both types of patterns are "unanchored". This means that patterns do not have to match the entire string, but can begin and
end the match anywhere in the string (as long as everything else
matches). Use ^ to match the beginning of a string, and $ to
match the end. Note that if you do not wait for the end of a
string, your responses can easily end up in the middle of the
string as they are echoed from the spawned process. While still
producing correct results, the output can look unnatural. Thus,
use of $ is encouraged if you can exactly describe the characters
at the end of a string.Note that in many editors, the ^ and $ match the beginning and end of lines respectively. However, because expect is not line oriented, these characters match the beginning and end of the data (as opposed to lines) currently in the expect matching buffer. (Also, see the note below on "system indigestion.")
-ex:the pattern to be matched as an "exact" string. No interpretation of *, ^, etc is made (although the usual Tcl conventions must still be observed). Exact patterns are always unanchored.
-nocase:大寫輸出視為小寫。不影響 pattern。
While reading output, more than 2000 bytes can force earlier
bytes to be "forgotten". This may be changed with the function
match_max. (Note that excessively large values can slow down the
pattern matcher.) If patlist is full_buffer, the corresponding
body is executed if match_max bytes have been received and no
other patterns have matched. Whether or not the full_buffer key‐
word is used, the forgotten characters are written to ex‐
pect_out(buffer).If patlist is the keyword null, and nulls are allowed (via the
remove_nulls command), the corresponding body is executed if a
single ASCII 0 is matched. It is not possible to match 0 bytes
via glob or regexp patterns.Upon matching a pattern (or eof or full_buffer), any matching and
previously unmatched output is saved in the variable ex‐
pect_out(buffer). Up to 9 regexp substring matches are saved in
the variables expect_out(1,string) through expect_out(9,string).
If the -indices flag is used before a pattern, the starting and
ending indices (in a form suitable for lrange) of the 10 strings
are stored in the variables expect_out(X,start) and ex‐
pect_out(X,end) where X is a digit, corresponds to the substring
position in the buffer. 0 refers to strings which matched the
entire pattern and is generated for glob patterns as well as reg‐
exp patterns. For example, if a process has produced output of
"abcdefgh\n", the result of:
expect "cd"is as if the following statements had executed:
set expect_out(0,string) cd
set expect_out(buffer) abcdand "efgh\n" is left in the output buffer. If a process produced the output "abbbcabkkkka\n", the result of:
expect -indices -re "b(b*).*(k+)"is as if the following statements had executed:
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) abbbcabkkkkand "a\n" is left in the output buffer. The pattern "*" (and -re ".*") will flush the output buffer without reading any more output from the process.
Normally, the matched output is discarded from Expect's internal
buffers. This may be prevented by prefixing a pattern with the
-notransfer flag. This flag is especially useful in experiment‐
ing (and can be abbreviated to "-not" for convenience while ex‐
perimenting).The spawn id associated with the matching output (or eof or
full_buffer) is stored in expect_out(spawn_id).-timeout:the current expect command to use the following value as a timeout instead of using the value of the timeout variable.
By default, patterns are matched against output from the current
process, however the -i flag declares the output from the named
spawn_id list be matched against any following patterns (up to
the next -i). The spawn_id list should either be a whitespace
separated list of spawn_ids or a variable referring to such a
list of spawn_ids.For example, the following example waits for "connected" from the current process, or "busy", "failed" or "invalid password" from the spawn_id named by $proc2.
expect {
-i $proc2 busy {puts busy\n ; exp_continue}
-re "failed|invalid password" abort
timeout abort
connected
}The value of the global variable any_spawn_id may be used to match patterns to any spawn_ids that are named with all other -i flags in the current expect command. The spawn_id from a -i flag with no associated pattern (i.e., followed immediately by another -i) is made available to any other patterns in the same expect command associated with any_spawn_id.
The -i flag may also name a global variable in which case the
variable is read for a list of spawn ids. The variable is reread
whenever it changes. This provides a way of changing the I/O
source while the command is in execution. Spawn ids provided
this way are called "indirect" spawn ids.Actions such as break and continue cause control structures
(i.e., for, proc) to behave in the usual way. The command
exp_continue allows expect itself to continue executing rather
than returning as it normally would.This is useful for avoiding explicit loops or repeated expect
statements. The following example is part of a fragment to auto‐
mate rlogin. The exp_continue avoids having to write a second
expect statement (to look for the prompt again) if the rlogin
prompts for a password.
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
}For example, the following fragment might help a user guide an
interaction that is already totally automated. In this case, the
terminal is put into raw mode. If the user presses "+", a vari‐
able is incremented. If "p" is pressed, several returns are sent
to the process, perhaps to poke it in some way, and "i" lets the
user interact with the process, effectively stealing away control
from the script. In each case, the exp_continue allows the cur‐
rent expect to continue pattern matching after executing the cur‐
rent action.
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
}By default, exp_continue resets the timeout timer. The timer is
not restarted, if exp_continue is called with the -continue_timer
flag. - expect_after [expect_args]
- works identically to the expect_before except that if patterns
from both expect and expect_after can match, the expect pattern
is used. See the expect_before command for more information. -
- expect_background [expect_args]
takes the same arguments as expect, however it returns immedi‐
ately. Patterns are tested whenever new input arrives. The pat‐
tern timeout and default are meaningless to expect_background and
are silently discarded. Otherwise, the expect_background command
uses expect_before and expect_after patterns just like expect
does.
When expect_background actions are being evaluated, background
processing for the same spawn id is blocked. Background process‐
ing is unblocked when the action completes. While background
processing is blocked, it is possible to do a (foreground) expect
on the same spawn id.
It is not possible to execute an expect while an expect_back‐
ground is unblocked. expect_background for a particular spawn id
is deleted by declaring a new expect_background with the same
spawn id. Declaring expect_background with no pattern removes
the given spawn id from the ability to match patterns in the
background.- expect_before [expect_args]
takes the same arguments as expect, however it returns immediately. Pattern-action pairs from the most recent expect_before
with the same spawn id are implicitly added to any following ex‐
pect commands. If a pattern matches, it is treated as if it had
been specified in the expect command itself, and the associated
body is executed in the context of the expect command. If pat‐
terns from both expect_before and expect can match, the ex‐
pect_before pattern is used.
If no pattern is specified, the spawn id is not checked for any
patterns.
Unless overridden by a -i flag, expect_before patterns match
against the spawn id defined at the time that the expect_before
command was executed (not when its pattern is matched).
The -info flag causes expect_before to return the current speci‐
fications of what patterns it will match. By default, it reports
on the current spawn id. An optional spawn id specification may
be given for information on that spawn id. For example
expect_before -info -i $proc
At most one spawn id specification may be given. The flag -indi‐
rect suppresses direct spawn ids that come only from indirect
specifications.
Instead of a spawn id specification, the flag "-all" will cause
"-info" to report on all spawn ids.
The output of the -info flag can be reused as the argument to ex‐
pect_before.- expect_tty [expect_args]
類似 expect,但讀 /dev/tty。
- expect_user [expect_args]
類似 expect,但讀 stdin。
- fork
分叉出子 process,成功時在子 process 回 0,在親 process 回子 process ID。失敗時,回 -1,不會建立子 process。
子 processes exit via the exit command, just like the original process. 子 processe 仍會寫 log 檔,親子都紀錄可能會混淆。
有些 pty 實作在多個 reader 或 writer 時會困惑,即使只是短暫的,因此 fork 後 spawning processes 較安全。
[待續]
參考
- man expect
- tcl 是一個高階的電腦語言,語法類似 shell script 與 C 語言之間。而 tk 是一個 GUI 發展工具,有 buttons、menus、listboxes、 scrollbars 等等。
- 書《Exploring Expect》介紹 expect 和 tcl。
- Expectk 是 Expect 和 Tk 的混合,使用長參數名稱。libexpect 可以直接和 C 或 C++ 使用,而不用 Tcl。
- 待讀:Tcl/Tk 學習筆記
沒有留言:
張貼留言