Getting work done while you're fishing -- with expect

Not exactly an unknown command, but one that seldom reaches the Unix top ten, expect is an interesting Unix tool that allows you to run tasks that are designed to be interactive -- even when you're nowhere to be found.

For example, when an install script expects to collect a couple pieces of information from the person running it, you can set it up to run unaccompanied. When you have set up a series of automated tasks that need to be run before a new service goes live (and some of these require some interaction with the person running them), you can set them all to run overnight when no other service will be affected.

Obviously not your own scripts as, presumably, you can design those to accept parameters rather than question/answer sequences, expect can be very handy for everything from crafting an interaction between servers to running time-consuming installations that you'd prefer be done after hours.

Installing expect is easy. The expect package can be installed using one or the other of these commands on most Linux systems:

sudo yum install expect
sudo apt-get install expect

You'll then find the tool in /usr/bin. So, you can start your expect scripts with the shebang line shown below.

#!/usr/bin/expect

You can run expect commands on the command line. The basic syntax is shown below.

expect [ -dDinN ] [ -c cmds ] [ [ -[f|b] ] cmdfile ] [ args ]

Here are some examples of very basic expect commands:

$ expect -c 'expect "\n" {send "hello\n"}'

hello

Once the person at the keyboard presses the enter key, the system comes back and says "hello".

$ expect -c 'expect "hi" {send "good morning\n"}'
hi
good morning

In this one, expect is expecting you to type "hi".

In either of the examples shown above, expect is only going to wait ten seconds before it gives up and drops you back to the command line. This is its default timeout. You can change that if you need to a longer or shorter time periond by using a set timeout command. No patience with someone expected to type "hi"? Give him only two seconds:

expect -c 'set timeout 2; expect "hi" {send "good morning\n"}'

You can put your expect commands into scripts by using the shebang line shown above and your expect commands. This script will exit after ten seconds (default timeout) or as soon as you type "hello".

#!/usr/bin/expect

expect hello

This one waits up to a minute and sends a friendly acknowledgement if you type "hello". If the person running this script simply sits there sipping her coffee and doesn't respond, however, the script will still send the friendly message.

#!/usr/bin/expect

set timeout 60
expect "hello"
send "Hello there, cutie!  What are you up to today?\n"

Want to withhold the friendly message for anyone too crabby or too preoccupied with her morning coffee to type "hello"? No problem. Modify the script above with the added { and } and the friendly message will be dependent on a response.

#!/usr/bin/expect

set timeout 20
expect "hello" {
send "Hello there, cutie!  What are you up to today?\n"

One of the most heavily used expect commands is spawn. In fact, for many expect scripts, the spawn command is the first thing you do as this command spawns some process that your script needs to interract with to get some important work done.

Say we have a script called "add" that adds two numbers together.

#!/bin/bash

echo -n "Enter the first number: "
read num1
echo -n "Enter the second number: "
read num2
sum=`expr $num1 + $num2`
echo $sum

And now we want out expect script to interract with that process.

#!/usr/bin/expect

set timeout 30

spawn "./add"

expect "Enter the first number:" { send "111\r" }
expect "Enter the second number:" { send "365\r" }

interact

Using commands such as these, you can provide information to the interactive processes that you want to run on their own in your absence.

Some of the other expect commands include:

  • expect -- this command should be thought of as a loop. It waits for the string specified until it appears
  • send -- sends a string to the process (or the screen)
  • send_user -- sends output to standard out
  • log_user -- can be used to stop output (log_user 0) or turn it back on (log_user 1)
  • exp_interval -- provides a debug mode (exp_interval 1)
  • set -- assigns values to variables
  • close -- closes the connection to a process
  • interract -- returns control to the user

When to use expect:

You should consider using expect ...

  • only after you've tested the install on one system to make sure it works as expected (excuse the pun!)
  • only if the answers that you need to provide within your expect scripts don't present any security risks (e.g., exposing passwords)

Expect scripts can get quite complicated and, yes, there's an entire book written on the tool -- Exploring Expect: A Tcl-based Toolkit for Automating Interactive Programs. http://shop.oreilly.com/product/9781565920903.do

Copyright © 2015 IDG Communications, Inc.

The 10 most powerful companies in enterprise networking 2022