How to Automate Shell Scripts with Expect Command

We’ll show you how to automate shell scripts with expect command. The “Expect” name comes from the concept of sending/waiting for sequences popular by uucp, kermit and various modem management programs. However, not like uucp, Expect is generalized so it can be executed as a user-level command with any program and task in mind. Expect can communicate with multiple programs at the same time. In other words the Expect is a program that talks to a variety of interactive programs according to the script. 

First you need to install the expected package in your system because it is not installed by default. You can install it using the following command:

$ apt-get install expect

Or on Red Hat based systems like CentOS:

$ yum install expect

Once installed, you’ll see the expect interpreter as “/usr/bin/expect”.

Usage of Expect command

In order to execute the list of command, the expect command reads from a cmd file. The Expect command could be referred to implicitly to systems that support the #! notation by marking the script as executable and making the first line in the script:

#!/usr/local/bin/expect -f

The /usr/local/bin path is just an example. Of course, the path must be exactly where the Expect is located.

The -c flag prelude a command to execute before any of the scripts. To prevent breaking by the shell the command has to be quoted. We can use this option multiple times. Multiple commands can be executed with only one -c by dividing them with a semicolon. The commands are executed in the order in which they appear.

The -d flag provides a certain diagnostic output, which mainly reports the internal activity of the commands like expect and interact. This flag has the same effect as “exp_internal 1” at the beginning of the Expect script, plus the version of Expect is printed.

The -D flag provides an interactive debugger. An integer value should be followed. If the value is non-zero the debugger will take control before the next Tcl procedure or if it is pressed ^C or the breakpoint is interrupted, or another appropriate command for the debugger appears in the script. This option is listed as -Debug if you are using Expectk.

The -f flag begins a directory from which to read commands. This flag is available as a choice because it is handy when using #! notation so can submit the other arguments to the command line. This option is identified as -file If you are using Expectk.This option is identified as -file If you are using Expectk.

Typically, the command file is read into memory and executed in its totality. Sometimes it is desirable to read files on one line at a time. In order to force arbitrary files to be handled this way, we can use the -b flag. This option is specified as -buffer if you are using Expectk.

If the string “-” is supplied as a filename, instead of the standard input, it is read. To read from a file actually named “-” use the “./-” string.

The -i flag causes Expect to interactively prompt for commands rather than reading them from a file. Prompting is terminated via the exit command or upon EOF. The -i flag is assumed if neither a command file neither -c is used. Once using Expectk, this feature is specified as -interactive.

— could also be used to delimit the end of the choices. This can be useful if you want to pass the argument as an option to your script, and not to be interpreted by the Expect. This may be usefully be placed within the #! line to avoid any flaglike interpretation by Expect. For example, the original arguments together with the script name may be left within the variable argv .

#!/usr/local/bin/expect --

The file $ exp_library/expect.rc is automatically generated if it is present unless the -N flag is used. (When using Expectk, this feature is specified as -NORC.) instantly once this, the file ~/.expect.rc is sourced automatically, unless the -n flag is used. If the environment variable DOTDIR is defined, it’s treated as a directory and .expect.rc is read from there. once using Expectk, this feature is specified as -norc. This sourcing happens only when executing any -c flags.

-v causes Expect to print its version number and exit. The appropriate flag in Expectk, which uses long-flags names, is a -version.

The optional arguments are created in the list and stored within a variable called argv and. argc is initialized to the length of argv.

Argv0 is defined as the script name or binary if the script is not used. For instance, the following prints out the name of the script and also the first 3 arguments:

The following four Expect commands are used when automating any interactive processes.

send – The send command is used to send a response to a script or program.
expect – The expect command waits for entry. In other words is waiting for the program output.
spawn – The spawn command is used to launch a script or program such as shell, SSH, FTP, Telnet, SCP and so on. Basically, it will start a script or a program.
interact – The interact command allows you to interact with your program. This means that the interact command it says to expect command to release the terminal so you can write things and do things.

Expect command examples

Let’s write a shell script that will ask some questions, and then we can make an Expect script that will answer those questions.

We will begin by creating a shell script:

#!/bin/bash

echo "Hello, how are you doing today?"

read $ANSWER

echo "May I ask you some questions?"

read $ANSWER

echo "What is your favorite color?"

read $ANSWER

Next, we will type the Expect scripts that will answer on the questions automatically:

#!/usr/bin/expect -f

set timeout -1

spawn ./questions

expect "Hello, how are you doing today?\r"

send -- "Thanks, I am great.\r"

expect "May I ask you some questions?\r"

send -- "Of course\r"

expect "What is your favorite color?\r"

send -- "White\r"

expect eof

The expect command path is defined in the first line which is #!/usr/bin/expect. On the second line of code, we have disabled the timeout. Then run our script using the spawn command. We can use spawn to run any interactive script or program we want. The other rows that remain are the Expect script that connects to our shell script. Last line if the end of the file which means is the end of the interaction.

Now it’s time to run the script, just make sure the script is executable.

If the script is not executable, then you can use the following command:

$ chmod +x ./answerbot

And of course, the execute command to run our script:

$./answerbot

From this example we can see that we did not communicate with our script at all, the Expect program did the job for us.

The above method can be used for any interactive script or program. Although the script above is very simple to write, perhaps the Expect script is a little inconvenient for some people, you have it well.

Using autoexpect command

You can the use autoexpect command if you want to build an expect script automatically.

The autoexpect command works like the expect command, the deference is that the autoexpect will build the automation script for you. The script you want to automate will be passed to autoexpect as a parameter and when you answer the questions and your answers will be saved in a file.

$ autoexpect ./questions

After we run the above command, a single file will be generated called script.exp this file will contain the same code as we did on the previous example but also will have some add-ons that we will skip for now.

It should look like this:

# -Don
#

set timeout -1
spawn ./questions
match_max 100000
expect -exact "Hello, how are you doing today?\r
"
send -- "Fine thanks you"
expect -exact "Fine thanks you"
send -- "\r"
expect -exact "\r
May I ask you some questions?\r
"
send -- "Sure\r"
expect -exact "Sure\r
What is your favorite color?\r
"
send -- "White\r"
expect eof

When we run the auto-generated file script.exp, we can see the same answers as awaited:

spawn ./questions
Hello, how are you doing today?
Fine thanks you
May I ask you some questions?
Sure
What is your favorite color?
White

There are many commands that produce a variable output, such as FTP programs, the expected script may fail or get stuck. To resolve this problem, you can use wildcards for the variable data to make your script more flexible.

Working with Variables

In the next example, we will show you how to set the variables and how to use them with Expect script.

The set command is using to define variables in Expect scripts like this:

set TESTVAR 5

To access the variable, precede it with $ like this $EXAMPLE

To define the arguments of the command line in the Expect scripts, we are going to use the following syntax:

set TESTVAR [lindex $argv 0]

Here we define a variable TESTVAR which is equal to the first given argument.

You can get the first and the second arguments and store them in variables like this:

set mood [lindex $argv 0]

set color [lindex $argv 1]

Let’s add variables to our script:

#!/usr/bin/expect -f

set mood [lindex $argv 0]

set color [lindex $argv 1]

set timeout -1

spawn ./questions

expect "Hello, how are you doing today?\r"

send -- "Im $mood\r"

expect "May I ask you some questions?\r"

send -- "Of course\r"

expect "What is your favorite color?\r"

send -- "$color\r"

expect eof

Now try to run the Expect script with some parameters to see the output:

$ ./answerbot SomeMood SomeColor

We just created our dynamic automated Expect script.

Using conditional tests

By using braces as shown in the following example you can create conditional tests:

expect {

"example" { send -- "send example\r" }

"*lesson" { send -- "send lesson\r" }

}

Now we will change our script to return different conditions, and after that, we will change the expect script to deal with these conditions.

We are going to imitate different expectations with the following script:

#!/bin/bash

let number=$RANDOM

if [ $number -gt 24000 ]

then

echo "What is your favorite food?"

else

echo "What is your favorite drink?"

fi

read $ANSWER

A random number is generated every time you start the script and based on that number, we have set to return different expectations.

The next part is to make our expect script will deal with that.

#!/usr/bin/expect -f

set timeout -1

spawn ./questions

expect {

"*food?" { send -- "Pizza\r" }

"*drink?" { send -- "Lemonade\r" }

}

expect eof

If the script hits the food output, the expect script will send pizza and if the script hits drink output the expect script will send lemonade.

Example with expect command in if/else conditions

The following example is how to use if/else clauses in expect scripts:

#!/usr/bin/expect -f

set NUM 14

if { $NUM < 99 } {

puts "\Smaller than 99\n"

} elseif { $NUM > 99 } {

puts "\Bigger than 99\n"

} else {

puts "\Equals 99\n"

}

Note: The opening brace needs to be on the same line.

Using while loops

In expect language when we are using while loops we need to use braces like in the following example:

#!/usr/bin/expect -f

set NUM 1

while { $NUM <= 10 } {

puts "\nNumber is $NUM"

set NUM [ expr $NUM + 1 ]

}

puts ""

Example with For Loops

To create a for loop in expect, we need to specify three fields, like in the following example:

#!/usr/bin/expect -f

for {set NUM 1} {$NUM <= 10} {incr NUM} {

puts "\nNUM = $NUM"

}

puts ""

How to use user-defined functions

In the next example, we will show you how to define a function by using the proc.

proc testfunc { TOTAL } {

set TOTAL [expr $TOTAL + 1]

return "$TOTAL"

}

And after that you can use them.

#!/usr/bin/expect -f

proc testfunc { TOTAL } {

set TOTAL [expr $TOTAL + 1]

return "$TOTAL"

}

set NUM 1

while {$NUM <= 10} {

puts "\nNumber $NUM"

set NUM [testfunc $NUM]

}

puts ""

Our last example will be about the interact command.

Sometimes the expect script contains some sensitive information that you do not want to share with other users who use your expect scripts, such as passwords or other data, so you want your script to take this password from you and continue automation normally.

The interact command will return the control back to the keyboard. When this command is executed, the expect command will begin to read from the keyboard.

This shell script will ask for the password as presented in the example below:

#!/bin/bash

echo "May I ask who are you?"

read $ANSWER

echo "Can you provide me with your password?"

read $ANSWER

echo "What is your favorite color?"

read $ANSWER

Now we will create the expect script that will prompt for the password:

#!/usr/bin/expect -f

set timeout -1

spawn ./questions

expect "*who are you?\r"

send -- "Hello my name is Thomas\r"

expect "*password?\r"

interact ## return

send "\r"

expect "*color?\r"

send -- "White\r"

expect eof

After you enter your password type ## if you want the control to return back from the keyboard to the script.

The expected language is ported into many languages like C #, Java, Perl, Python, Ruby, and Shell with almost the same concepts and syntax.

Expect scripting language is used in QA, network measurements, such as echo response time, automating file transfer, upgrades, updates, and many other uses

We hope that we help you to understand some of the most important aspects of Expect command, autoexpect command and how to use them.


If you liked this post on How to automate shell scripts with expect command, please share it with you friends on social media, or if you have any question regarding this blog post, please leave a comment and one of our system administrators will reply to it. Thanks!

1 thought on “How to Automate Shell Scripts with Expect Command”

  1. Would like to know how run `autoexpect` as though there were no argument (i.e., shell user interaction), but supplying the input lines in a file. For example, in your scenario the prompt never appears, but I want the prompt.

    Reply

Leave a Comment