== Expect example == Many people come to the #bash IRC channel asking about [[https://core.tcl-lang.org/expect/index|Expect]]. Expect is a package written in and for Tcl, so it's not supported by the #bash channel. Moreover, some people seem to think that they should call `expect` as a command from their bash scripts. This is not how it's best used. Expect is a Tcl package, and also a standalone tool incorporating a Tcl interpreter. If you use it, you will be writing a Tcl program, not a bash script. That said, it doesn't hurt to show an example of how to use it. There seems to be a demand for it. So, let's go for it. === The program we're driving === Expect is used to "drive" an interactive program using a script. The script needs to have some idea of how the interactive program will work, so that it can anticipate certain key pieces of output, and know what input to provide. Therefore, the first thing you should do is actually ''run'' the interactive program yourself, and try to find all the possible responses that you'll need to handle. We're going to drive a simple number-guessing game. Here's the game: {{{#!highlight bash #!/bin/bash number=$((RANDOM % 100 + 1)) while read -r -p 'Your guess: ' guess; do # Input validation goes here. Omitted for this example. if ((guess == number)); then echo 'You won!' break elif ((guess < number)); then echo 'Too small, try again.' else echo 'Too large, try again.' fi done }}} If you run this in a terminal and interact with it, you'll see that its output consists of either (1) a single line telling you whether you've won, or guessed too high, or guessed too low; or (2) a prompt. When you see the prompt, you're supposed to type a number and press Enter. So, that's what our Expect script will need to do. === The Expect script === In addition to handling the basic responses from the game, we need some sort of strategy for how to actually play it. The naive way would be to guess every number from 1 to 100 until we win, and that would work. But the optimal solution is of course to use a binary search. This means we need to keep some variables that track the lower and upper limits of the current possible range. Each time we guess, we choose the number in the middle of the range. If we guess too low, then we move the lower bound up to our guess. If we guess too high, we move the upper bound down to our guess. Here's the Expect script. It's written for a system where `expect` is installed as a standalone tool in `/usr/bin/expect`. If your system has it in a different place, you can change the shebang. If you only have it installed as a Tcl package, then you may need to use a `tclsh` shebang, and load the package. {{{#!highlight tcl #!/usr/bin/expect -- set low 1 set high 101 set guess 51 spawn ./game expect { {You won} exit {Too small} { set low $guess exp_continue } {Too large} { set high $guess exp_continue } {Your guess:} { set guess [expr {($low + $high) / 2}] send "$guess\r" exp_continue } } }}} What do you need to know about this program? There are only a few important pieces. * The shebang says that this script is interpreted by `/usr/bin/expect`. This is an Expect script. It's not a shell script. * We use `spawn` to launch the game as a child process and set up all the magic for driving it. * We use `expect` for the main body of the driving script. The `expect` command doesn't automatically loop; we have to use `exp_continue` to make it keep iterating. * There are 4 possible responses that we handle. Three of them are informational, and we respond to them by either exiting (because the game is over), or by adjusting our variables. * The fourth response is a prompt. When we see this, we send our guess, followed by a carriage return (which is what the Enter key sends). * If we `set high 100` at the start of the program, we can't handle the number 100. Setting `high` to 101 allows us to guess the number 100. And there you have it. Now you know how to drive a number-guessing game using Expect. You can apply these same techniques to drive many other interactive programs. ---- CategoryTcl