August 3, 2006

Automate interactive transactions with Expect

Author: Michael Stutz

Did you ever wish you could automate your interaction with a program, making a script that can smartly handle an interactive session? You can -- with Expect, an extension to the Tcl programming language whose purpose is to communicate with interactive applications.

You can write Expect programs that automate live sessions, handling any tasks where a user interacts with the system. This suggests a multitude of uses, but where it has been most popularly applied is in software testing and in automating network transfers, such as site updates or downloads.

Expect is a product of the US government, having been created by Don Libes, a computer scientist at the National Institute of Standards and Technology (NIST). It has been around for years, and while its functionality has stayed the same, the reason for using it keeps changing.

"Expect has always been a 'hole-plugger' in the sense that it only has value until existing holes in other tools are plugged," Libes says. Many of the holes it plugged in the past -- like scripting outbound email messages -- have been filled by new or improved tools. But there's still no shortage of holes that Expect can handle.

"After all, tools like telnet and ssh still offer very limited control, so Expect is useful there," Libes says. "Expect will also remain useful when dealing with custom software and hardware, where no one has time to embed any kind of control language, or proprietary stuff where there's no way to do it if the vendor hasn't provided a similar mechanism, or the fusion of tools which were never designed to work together."

Basic commands

The first thing everybody seems to try when learning Expect must be how to use it to script a call to the passwd command. The autopasswd program is one of the examples that Expect comes with. When you run it (as root) with the arguments of a username and password, it calls the passwd command and resets the given user's password. Very simple -- but also quite useful, because you can't use normal shell redirection to do it. Now imagine this tiny automation repeated 1,000 times for a batch of users, and you start to see how handy Expect can be. Whenever you have to type something over and over again, Expect can completely automate the interaction. And with the Tk toolkit, it's a trivial matter to build graphical X11 dialogs around your Expect programs.

The meat of the autopasswd program is just this:

set password [lindex $argv 1]
spawn passwd [lindex $argv 0]
expect "password:"
send "$password\r"
expect "password:"
send "$password\r"
expect eof

You can probably guess the meaning of the commands -- first, the password variable is defined as the second command-line argument; then spawn starts a new process, running the arguments given to it -- in this case the passwd command. Then the expect command waits for the text "password:" -- and when it comes, the send command sends the new password to the process.

This example neatly encapsulates the whole raison d'etre of Expect, and contains almost all of its important commands. In addition to these, the other core command is interact, which passes control of the process back to the user, who can interact with it directly via standard input as normal. Control can be passed back to the Expect program in various ways, including by what the user types or by what is output by the process.

Get the weather

One of the more famous and easily demonstrable Expect applications is weather, another example script that comes with the standard distribution. It uses the Weather Underground's excellent telnet interface to its weather server to get an up-to-the-minute bulletin from the National Weather Service.

Run weather with the three-letter city code you'd like to get a report on (a lot of Linux systems have a list installed at /usr/share/doc/miscfiles/airport.gz). You'll see Expect opening the telnet connection and choosing the city weather report from a menu (if you want to get fancy, all this cruft can be wiped out with the user_out command), and then the actual weather bulletin is output:

$ weather nyc... connection messages ...
Weather Conditions at 11:51 AM EDT on 27 Jul 2006 for New York JFK, NY.
Temp(F)    Humidity(%)    Wind(mph)    Pressure(in)    Weather
========================================================================
  81          74%           SSW at 10       30.00      haze

Forecast for New York, NY
1013 am EDT Thu Jul 27 2006

.This afternoon...Partly sunny with a slight chance of showers and
thunderstorms. Humid with highs in the upper 80s...cooler near the ocean.
South winds 10 to 15 mph. Chance of rain 20 percent.
.Tonight...Partly cloudy. A chance of showers and thunderstorms mainly
after midnight. Patchy fog after midnight. Humid with lows in the mid
70s. Southwest winds 10 to 15 mph. Chance of rain 30 percent.
... more ...
$

Examples galore

The Expect distribution comes with about 50 example scripts in all. In addition, the Expect distribution site at NIST has a directory of scripts contributed by users that are fun to browse through.

These examples run the gamut from the silly -- a real-time simulation of someone typing out the "99 Bottles of Beer On The Wall" song -- to the seriously useful. There's multixterm, for instance, which lets you open multiple xterms and send the keystrokes from your input window to all of them simultaneously. And xkibitz lets two (or more) users share the same shell or other program from their terminals -- an excellent hands-on training tool.

These programs are always informative -- even the beer song demonstrates how pseudo-random input can be generated and passed in real-time to a process, perhaps for testing purposes -- and they're worth studying to give you ideas of the diverse ways that Expect can be used.

Click Here!