Expect references of interest to Cameron Laird

I originally wrote this page in late 1995. Since then, I've moved most of my notes on Expect to the Tcl-ers' Wiki. I do want to offer, though, that I've published such pieces on Expect as Android

"Expect is, after all, a tool made for dealing with crappy interfaces. (If they were good interfaces, you wouldn't need Expect in the first place.)" More formally, Expect's home page begins: "Expect is a tool for automating interactive applications ..."

Don Libes keeps his latest snapshot expect publicly available, along with an exemplary FAQ. Even more current sources are available through CVS [give link ...].

How should Expect beginners begin? Many, many books for system administrators introduce Expect; Don's own book is a model of exposition [detail its virtues ...]; and the distribution includes marvelous examples. I constantly urge programmers to learn early about the -d command-line switch, as well as autoexpect. Great manual pages from the distribution explain these and much more. I often run across pleas for "collections of scripts" that do common tasks such as password fiddling and FTP operations; there's something about these that seems mistaken, or at least mismatched, to me, although I can't yet articulate it. My advice: install the standard distribution, and read its documentation.

I constantly refer newcomers to the publisher's catalogue description of Mr. Libes' book on Expect for its maximally-efficient one-paragraph introduction to Expect and, more generally, to the possibilities Tcl affords.

As of November 1996, I mostly use version 5.21.3 of Expect with 7.6 of Tcl, although Mr. Libes prescribes 7.5.

Several tutorials are available.

A different FAQ for Expect.

Good news! Expect is available for NT.

One major reason to use Expect is for network management.

expecTerm

Pythonians achieve some of Expect's functionality with the telnetlib.py module Version 1.5 introduces [give cross-ref].

[Explain published work.]

Examples

remotely_execute, a telnet interface

This is a good example because it's in real-life use. It's a bad example, because I haven't documented it adequately.

Skip ahead to the remotely_execute comments; that's where the the most interesting action is.

########
#
#	establish_telnet_session
#
#	Copyright Cameron Laird 1995.
#
#	Side effect:  it puts an entry in the globally-accessible
#	     telnet_id hash.
#
#	These sessions should be closed, eventually.  I make no
#	     provision for that in this example.
#
#	Fault:  many log-ins in fact ask for a TERM value.  This
#	     implementation makes no provision for this possibility,
#	     and simply responds inscrutably.
#
########
proc	establish_telnet_session {host user password current_prompt} {
	global telnet_id
#	Think about a better way to manage match_max.
match_max	10000

# Unused ...
	set	cl_process_id [spawn telnet $host]
	set	telnet_id($host) $spawn_id

	expect	"login: "
	send	"$user\r"
	expect	"Password:"
	send	"$password\r"
	expect	$current_prompt
}


########
#
#	format_expect_result
#
#	Copyright Cameron Laird 1995.
#
#	I've forgotten the point of this.  I need to document it
#	     sometime.
#
########
proc format_expect_result {unformatted} {
	set first [string first \n $unformatted]           
	set last [string last \n $unformatted]
	incr first
	set last [expr $last - 2]
	return [string range $unformatted $first $last]
}


########
#
#	one_remote_command
#
#	Copyright	Cameron Laird 1995.
#
#	Is it better to anchor the expect string?  Think about that, later.
#
########
proc	one_remote_command {this_spawn_id current_prompt one_command} {
#	Document this.
		# If I don't trap this, sometimes $expect_out(buffer)
		#    is undefined.  I don't understand this, and haven't
		#    time now to learn more.
	set expect_out(buffer) {}

	send -i $this_spawn_id -- "$one_command\r"
	expect -i $this_spawn_id timeout timeout_error \
						"$current_prompt" {}
	return $expect_out(buffer)
}	


########
#
#	remotely_execute
#
#	Copyright	Cameron Laird 1995.
#
#	This is the principal entry point for this block.  Once these
#	     procedures are known, one can begin "remotely_execute .."-
#	     ing without any other initialization.
#
#	Yup; this invites ($user,$password) to be left lying around
#	     in some public place.  More on that, later.
#
#	The semantics here are a bit arcane.  remotely_execute connects
#	     to $host, executes $args in the directory $directory, and
#	     returns the results.  If there's already a connection to
#	     $host, it ignores ($user,$password), and changes directory
#	     relative to wherever it last was.  It's FAR safer to use
#	     fully-qualified $director-ies.
#
#	Typical values for $shell_prompt_string:  "# "; "> "; "} "; ...
#
#	Typical invocations:
#	     remotely_execute host13 cl mypassword $prompt /tmp du -s *
#	     remotely_execute host13 "" "" $prompt ~ ls -lt
#
#	More sophisticated escaping of $args might matter for some.  I've
#	     had no problems to this point.
#
########
proc	remotely_execute {host user password shell_prompt_string \
			directory args} {
	global telnet_id

		# Memoize:  if we've already connected to $host, use that
		#     session; otherwise, launch a new one.
	if [catch {set telnet_id($host)}] {
		establish_telnet_session $host \
					$user $password $shell_prompt_string
	}

# This deserves explicit exception-handling.  Later.
	one_remote_command $telnet_id($host) $shell_prompt_string \
						"cd \"$directory\""
	return [format_expect_result \
		[one_remote_command $telnet_id($host) $shell_prompt_string \
						"$args"]]
}	


proc	timeout_error {} {
	global timeout

	puts	"Time-out error ($timeout); please contact C. Laird."
	exit
}

Cameron Laird's index to Expect/claird@phaseit.net