Programming in Expect:
A Bulletproof Interface
This article assumes the
reader has a thorough understanding of the basics of the Expect scripting
language and is looking for advanced solutions. For more on Expect,
In the design of automated systems
in Expect, one of the more difficult hurdles many programmers encounter
is ensuring communication with ill-behaved connections and remote terminals.
procedure detailed in this article provides a means of ensuring communication
with remote systems and handles editing and rebroadcast of the command
line. Where a programmer would usually send a command line and then expect
the echo from the remote system, this procedure replaces those lines of
code and provides the most reliable interface I have come across.
Features of this interface include:
Communication with local processes
(i.e. those running on the same workstation as the expect process) is typically
not problematic and does not require the solutions detailed in this article.
External processes, however, can create a number of problems that may or
may not affect communication, but will affect an automated system's ability
to determine the success of the communication. In cases where it
is corrupted, it is not always immediately obvious: a corrupted command
may trigger an error message, but data which has been corrupted may still
be considered valid and the error would not show up immediately, and may
cause a variety of problems. This is why it is necessary to ensure
that the entire string that is transmitted is properly received echoed
by the remote system.
Guarantees transmission via
remote system echo
Tolerates remote terminal control
codes and garbage characters in the echo of the sent string
Persistence of attempts and
hierarchy of methods before declaring a failure
Interactively edits and retransmits
command lines that cannot be verified
Maintains its own moving-window
diagnostics files, so they are small and directly associated with the errors
The basic idea of this interface
is to send the command string except for its terminating character (usually,
a carriage return) and look at the echo from the remote system. If
the two can be matched using the regular expressions in the expect clauses,
then the terminating character is sent and transmission is considered successful.
If success cannot be determined, the command line is cleared instead of
being sent, and alternative transmission modes are used.
In many cases, nothing more
than expecting the exact echo of the string is sufficient. If you're
reading this article, though, I suspect that you've encountered some of
the problems I have when programming in Expect, and you're looking for
the solution here. If you're just reading out of interest, the problems
arise when automating a session on a machine off in a lab, or on the other
side of the world. Strange characters pop up over the connection,
and the terminal you're connected to does weird things with its echo, but
everything is working. It becomes very difficult to determine if
what was sent was properly received when you have noise on the connection,
terminal control codes inserted in the echo, and even server timeouts between
the automation program and the remote session. This interface survives
all of that, and if it can't successfully transmit the string, it means
that the connection to the remote system has been lost.
The code provided in this
article is executable, but needs to be incorporated into any system in
which it is to be used. Ordinarily, system-dependent commands need
to be added based on the needs of the target system. Also, this code
uses simple calls to the puts command to output status messages - these
should be changed to use whatever logging mechanism is used by the rest
of the system. A final caveat, and I can't emphasize this enough:
always wear eye protection.