Science and technology

Study Expect by writing and automating a easy recreation

While attempting to automate my workflow, I stumble on a configuration utility that defied significant automation. It was a Java course of that did not help a silent installer, or help stdin, and had an inconsistent set of prompts. Ansible’s count on module was insufficient for this process. But I discovered that the count on command was simply the instrument for the job.

My journey to study Expect meant learning a bit of Tcl. Now that I’ve the background to create easy applications, I can higher study to program in Expect. I believed it will be enjoyable to jot down an article that demonstrates the cool performance of this venerable utility.

This article goes past the everyday easy recreation format. I plan to make use of components of Expect to create the sport itself. Then I reveal the actual energy of Expect with a separate script to automate enjoying the sport.

This programming train reveals a number of basic programming examples of variables, enter, output, conditional analysis, and loops.

Install Expect

For Linux primarily based methods use:

$ sudo dnf set up count on
$ which count on
/bin/count on

I discovered that my model of Expect was included within the base working system of macOS:

$ which count on
/usr/bin/count on

On macOS, you may also load a barely newer model utilizing brew:

$ brew set up count on
$ which count on
/usr/native/bin/count on

Guess the quantity in Expect

The quantity guessing recreation utilizing Expect will not be that completely different from the bottom Tcl I utilized in my previous article

All issues in Tcl are strings, together with variable values. Code strains are finest contained by curly braces (Instead of attempting to make use of line continuation). Square brackets are used for command substitution. Command substitution is helpful for deriving values from different capabilities. It can be utilized straight as enter the place wanted. You can see all of this within the subsequent script.

Create a brand new recreation file numgame.exp, set it to be executable, after which enter the script beneath:

#!/usr/bin/count on

proc used_time {begin} {
	return [expr [clock seconds] - $begin]

set num [expr round(rand()*100)]
set starttime [clock seconds]
set guess -1
set rely 0

ship "Guess a number between 1 and 100n"

whereas { $guess != $num } {
	incr rely
	ship "==> "

	count on {
		-re "^([0-9]+)n" {
			ship "Read in: $expect_out(1,string)n"
			set guess $expect_out(1,string)

		-re "^(.*)n" {
			ship "Invalid entry: $expect_out(1,string) "

	if { $guess < $num } {
		ship "Too small, try againn"
	} elseif { $guess > $num } {
		ship "Too large, try againn"
	} else {
		ship "That's right!n"

set used [used_time $starttime]

ship "You guessed value $num after $count tries and $used elapsed secondsn"

Using proc units up a perform (or process) definition. This consists of the identify of the perform, adopted by an inventory containing the parameters (1 parameter {begin}) after which adopted by the perform physique. The return assertion reveals an excellent instance of nested Tcl command substitution. The set statements outline variables. The first two use command substitution to retailer a random quantity and the present system time in seconds.

The whereas loop and if-elseif-else logic ought to be acquainted. Note once more the actual placement of the curly braces to assist group a number of command strings collectively without having line continuation.

The large distinction you see right here (from the earlier Tcl program) is using the capabilities count on and ship relatively than utilizing places and will get. Using count on and ship type the core of Expect program automation. In this case, you employ these capabilities to automate a human at a terminal. Later you may automate an actual program. Using the ship command on this context is not way more than printing info to display screen. The count on command is a little more advanced.

The count on command can take a couple of completely different varieties relying on the complexity of your processing wants. The typical use consists of certainly one of extra pattern-action pairs comparable to:

count on "pattern1" {action1} "pattern2" {action2}

More advanced wants can place a number of sample motion pairs inside curly braces optionally prefixed with choices that alter the processing logic. The type I used above encapsulates a number of pattern-action pairs. It makes use of the choice -re to use regex processing (as an alternative of glob processing) to the sample. It follows this with curly braces encapsulating a number of statements to execute. I’ve outlined two patterns above. The first is Is meant to match a string of 1 or extra numbers:


 The second sample is designed to match the rest that isn’t a string of numbers:


Take word that this use of count on is executed repeatedly from inside a whereas assertion. This is a wonderfully legitimate method to studying a number of entries. In the automation, I present a slight variation of Expect that does the iteration for you.

Finally, the $expect_out variable is an array utilized by count on to carry the outcomes of its processing. In this case, the variable $expect_out(1,string) holds the primary captured sample of the regex.

Run the sport

There ought to be no surprises right here:

$ ./numgame.exp 
Guess a quantity between 1 and 100
==> Too small, strive once more
==> 100
Read in: 100
Too giant, strive once more
==> 50
Read in: 50
Too small, strive once more
==> 75
Read in: 75
Too small, strive once more
==> 85
Read in: 85
Too giant, strive once more
==> 80
Read in: 80
Too small, strive once more
==> 82
Read in: 82
That's proper!
You guessed worth 82 after 8 tries and 43 elapsed seconds

One distinction it’s possible you’ll discover is the impatience this model reveals. If you hesitate lengthy sufficient, count on timeouts with an invalid entry. It then prompts you once more. This is completely different from will get which waits indefinitely. The count on timeout is a configurable function. It helps take care of hung applications or throughout an surprising output.

Automate the sport in Expect

For this instance, the Expect automation script must be in the identical folder as your numgame.exp script. Create the automate.exp file, make it executable, open your editor, and enter the next:

#!/usr/bin/count on

spawn ./numgame.exp

set guess [expr round(rand()*100)]
set min 0
set max 100

places "I'm starting to guess using the number $guess"

count on {
     -re "==> " { 
        ship "$guessn"
        count on {
             "Too small" {
                 set min $guess
                 set guess [expr ($max+$min)/2]
             "Too large" {
                 set max $guess
                 set guess [expr ($max+$min)/2]
             -re "value ([0-9]+) after ([0-9]+) tries and ([0-9]+)" {
                 set tries  $expect_out(2,string)
                 set secs   $expect_out(3,string)

    "elapsed seconds" 

places "I finished your game in about $secs seconds using $tries tries"

The spawn perform executes this system you wish to automate. It takes the command as separate strings adopted by the arguments to move to it. I set the preliminary quantity to guess, and the actual enjoyable begins. The count on assertion is significantly extra sophisticated and illustrates the ability of this utility. Note that there isn’t a looping assertion right here to iterate over the prompts. Because my recreation has predictable prompts, I can ask count on to do some extra processing for me. The outer count on makes an attempt to match the sport enter immediate of `==>` . Seeing that, it makes use of ship to guess after which makes use of an extra count on to determine the outcomes of the guess. Depending on the output, variables are adjusted and calculated to arrange the following guess. When the immediate `==>` is matched, the exp_continue assertion is invoked. That causes the outer count on to be re-evaluated. So a loop right here is now not wanted.

This enter processing depends on one other habits of Expect’s processing. Expect buffers the terminal output till it matches a sample. This buffering contains any embedded finish of line and different unprintable characters. This is completely different than the everyday regex line matching you’re used to with Awk and Perl. When a sample is matched, something coming after the match stays within the buffer. It’s made out there for the following match try. I’ve exploited this to cleanly finish the outer count on assertion:

-re "value ([0-9]+) after ([0-9]+) tries and ([0-9]+)"

You can see that the internal sample matches the right guess and doesn’t devour the entire characters printed by the sport. The final a part of the string (elapsed seconds) continues to be buffered after the profitable guess. On the following analysis of the outer count on , this string is matched from the buffer to cleanly finish (no motion is equipped). Now for the enjoyable half, let’s run the complete automation:

$ ./automate.exp 
spawn ./numgame.exp
I'm beginning to guess with the quantity 99
Guess a quantity between 1 and 100
==> 99
Read in: 99
Too giant, strive once more
==> 49
Read in: 49
Too small, strive once more
==> 74
Read in: 74
Too giant, strive once more
==> 61
Read in: 61
Too small, strive once more
==> 67
Read in: 67
That's proper!
You guessed worth 67 after 5 tries and 0 elapsed seconds
I completed your recreation in about 0 seconds utilizing 5 tries

Programming and improvement

Wow! My quantity guessing effectivity dramatically elevated because of automation! A number of trial runs resulted in anyplace from 5-8 guesses on common. It additionally all the time accomplished in beneath 1 second. Now that this pesky, time-consuming enjoyable could be dispatched so rapidly, I’ve no excuse to delay different extra essential duties like engaged on my home-improvement initiatives 😛

Never cease studying

This article was a bit prolonged however nicely definitely worth the effort. The quantity guessing recreation supplied an excellent base for demonstrating a extra fascinating instance of Expect processing. I discovered fairly a bit from the train and was in a position to full my work automation efficiently. I hope you discovered this programming instance fascinating and that it lets you additional your automation objectives.

Most Popular

To Top