A small beginner-level example of using
Expect to feed a script to
tclsh The Sequential Version edit
This script reads a Tcl script and enters it into an interactive
tclsh.
#! /bin/env tclsh
package require Expect
proc tclprompt {} {
proc [lindex [info level 0] 0] {} {
return {\n%\s$}
}
return {%\s*$}
}
set timeout -1
set fh [open [lindex $argv 0]]
set script [split [read $fh][close $fh] \n]
spawn tclsh
set command {}
foreach line $script {
if {[set line [string trimright $line]] eq {}} {
continue
} else {
append command $line\r
}
if {[info complete $command]} {
expect -re [tclprompt] {
send $command
set command {}
}
}
}
expect -re [tclprompt]
Some interesting points:
Setting timeout to -1 allows expect to wait as long as necessary for the next prompt.
[tclprompt] uses a
$ to anchor the prompt to the end of the output. Expect is not line-oriented, so this is not foolproof.
[tclprompt] is implemented as a command rather than a variable because the first prompt is not preceded by a newline character, but subsequent prompts are, and manipulating the proc one time is more succinct than putting an extra conditional into the
foreach statement.
simply checking for "%" is less robust than checking for a newline followed by "%" followed by space followed by the end of output. It's generally a good idea to be as specific as possible when expecting a prompt.
The Event-Driven Version edit
Here is an event-driven version of the same thing (only tested on *nix):
#! /bin/env tclsh
package require Expect
proc tclprompt {} {
proc [lindex [info level 0] 0] {} {
return {\n%\s$}
}
return {%\s*$}
}
proc input {fh {command {}}} {
#remove the current event handler since leaving it in place seems to interact poorly with [expect]
fileevent $fh readable {}
if {$command ne {} && [info complete $command]} {
expect -re [tclprompt] {
send $command
}
fileevent $fh readable [list input $fh]
return
}
if {[eof $fh]} {
set ::done 1
expect -re [tclprompt] {
return
}
}
gets $fh line
if {[set line [string trimright $line]] ne {}} {
append command $line\r
}
fileevent $fh readable [list input $fh $command]
}
spawn tclsh
set timeout -1
set fh [open [lindex $argv 0]]
fconfigure $fh -blocking 0
fileevent $fh readable [list input $fh]
vwait done