Expect Command Tutorial in Linux With Example Usage

Sarath Pillai's picture
Expect Command In Linux

Automating repetitive task is a norm in the life of a system administrator. Mostly administrators write scripts in different programming languages to take care of this repetitive tasks.
 

The default choice for most Linux system administrators is to leverage the “BASH shell” and its scripting capabilities. Unlike Python, Ruby and Perl, Bash is not a full fledged programming language.
 

But it does provide a lot of programming features to get the job done(For example conditional statements, case statements, and a lot of built in features to make decisions in a script). As its not a full fledged language, you have to use other small programs to get your job done. 
 

Basically a script is nothing but a series of commands(mostly commands provided by different programs) arranged in a file that achieves an end result.
 

Some programs are interactive in nature(basically these programs were built by keeping human interaction in mind). For example, changing a user password in Linux. This requires the end user to type in the new password, when demanded by the “passwd” program, and then re-typing it again to verify it the second time.

 

Another example can be running a program like “fsck” to verify one of your file systems. Programs like “fsck”, is going to prompt you several questions and it expects answers to it before proceeding further(mostly answers like “yes” or “no” etc.)
 

So we need a method to automatically provide answers to these programs if we are to include them in our script.

 

This is where a program called “Expect” steps in.

The name of the program itself gives you an idea about its use case is. We tell "expect" what to look for while executing another interactive program. We also tell what the response should be.

 

Installing Expect is simple and straight forward. You can use apt-get or yum depending upon the flavor of Linux that you are using. For Red Hat based systems, execute the below command.

yum install expect

For Debian based or Ubuntu, execute the below command.

apt-get install expect

 

Lets first create an interactive script and then an "expect" program to deal with our interactive script. This way, we will be able to understand the use cases of expect.  First create a file named "interactive_program.sh" with the below content.

#!/bin/bash
echo "What is your name?"
read ANSWER
echo "How many dogs you have?"
read ANSWER
echo "How many cats you have?"
read ANSWER

 

We need to now give executable permission to the above file. This can be done using the below command.

chmod +x interactive_program.sh

 

We now have an interactive script that prompts several questions. Expect will execute this script and it will provide answers to these questions. We actually do not care much about the answers themselves, what we care about is the way "expect" takes care of this interactive script.

 

Now lets write another small expect script that will execute the above script and automatically submit answers to the questions. The first step is to find out where "expect" command is located.

whereis expect
expect: /usr/bin/expect /usr/bin/X11/expect /usr/share/man/man1/expect.1.gz

 

 

We now know that expect is located at /usr/bin/expect(This location can vary from system to system. So I recommend to fire the above "whereis" command to find the actual location on your machine.)

Create a file named "expect_script.sh" with the following content.

 

#!/usr/bin/expect
spawn ./interactive_program.sh
expect -exact "What is your name?\r"
send -- "Sam\r"
expect -exact "How many dogs you have?\r"
send -- "2\r"
expect -exact "How many cats you have?\r"
send -- "2\r"
expect eof

 

Now give executable permission as we did before using the below command.

chmod +x expect_script.sh

 

 

The very first line is a shebang. In this case its using /usr/bin/expect instead of /bin/bash. All commands inside this script will be executed under exepect program rather than bash. spawn will start our interactive script. Then we are telling "expect" to look for a line that says "What is your name?" followed by a newline charecter(indicated by \r).

Then we ask "expect" to send the input value of sam followed by a newline/return charecter (again indicated by \r).  We then ask expect to look for a line that says "How many dogs you have?" followed by a newline(\r). We then use send to send the input value of 2 followed by enter key(indicated by \r). The same method is used for the next question as well.

expect eof indicates that the script ends here.

 

You can now execute the file "expect_script.sh" and see all the responses given automatically by expect.

 

./expect_script.sh
spawn ./interactive_program.sh
What is your name?
Sam
How many dogs you have?
2
How many cats you have?
2

 

Lets now write a more practical example of expect. With some variables and values in it. 

We all know the fact that the Linux passwd program (which lets you change a users password. If you are root, you can change any users password using passwd program) prompts input from the end user.

It demands the password to be entered, and then re-entered for verification. Lets create an expect script that supports two parameters from the end user. These parameters will be username and password. Expect should then take care of changing that users password. Create a file named password_change.sh with the below content.

 

#!/usr/bin/expect
set user_name [lindex $argv 0]
set pass_word [lindex $argv 1]
spawn passwd $user_name
expect -exact "Enter new UNIX password: "
send -- "$pass_word\r"
expect -exact "\rRetype new UNIX password: "
send -- "$pass_word\r"
expect eof

 

 

Do not forget to execute chmod +x password_change.sh

This time we are using two variables inside our expect script. The first two lines, set user_name [lindex $argv 0] & set pass_word [lindex $argv 1] creates two variables named user_name and pass_word from the command line parameters provided. The first parameter will be username and  second will be password

The spawn line uses the user_name variable while triggering the passwd program. Use of variables in expect is done in pretty much the same way as in bash.

Similar to our previous expect script, this one also ends with an expect eof, and uses \r to indicate enter/return character. Lets now execute our script as shown below.

 

./password_change.sh testuser tfgh3425k
spawn passwd testuser
Enter new UNIX password:
Retype new UNIX password:
passwd: password updated successfully

 

You might be thinking that its really painful to construct an expect script, because it needs to be provided with the exact same new line characters and return characters and other input formats etc.  I agree. Its not easy to get an expect script working in the first attempt. To make our life easier, there is another helping program called as "autoexpect".

 

autoexpect is a command using which you can construct an expect script. Basically execute an interactive program using autoexpect command and it will create an expect script for that interactive program.

 

autoexpect is part of another package named expect-dev in the case of Ubuntu. So you need to install it first. In Red hat based systems autoexpect must already be installed along with expect.

 

apt-get install expect-dev

 

Using autoexpect is quite simple and straightforward.

 

You simply execute the interactive program by prepending autoexpect to it. For example, the script that we wrote previously can be provided as an argument to autoexpect as shown below. This will then create a file called script.exp. This is shown below.

 

autoexpect ./interactive_program.sh
autoexpect started, file is script.exp
What is your name?
Sarath
How many dogs you have?
3
How many cats you have?
0
autoexpect done, file is script.exp

 

 

Basically autoexpect will capture the behavior of the interactive program that is passed as argument and then create a expect script that does the same thing automatically. You need to basically change the content of script.exp to match the requirement you have(may be change the values, or add variables etc).

 

Apart from all these, expect also supports general programming capabilities like if else statements, case statements etc. These conditional statements supported by expect is slightly different from the standard bash shell conditionals.

 

Actually expect uses majority of the features provided by TCL language. TCL supports many different types of programming methods. Its simple and powerful.

 

Let's modify our password changing script and include a for loop to address it for multiple users. Remember, this for loop is not similar to bash for loop. This is TCL language for loop(which is used by expect, and as our script starts with a shebang of expect, this tcl statement works perfectly fine. This is because everything in the file will be interpreted by expect program.)

 

#!/usr/bin/expect
set l [list testuser testuser1 testuser2 testuser3]
set pass_word sf345234
foreach user_name $l {
    spawn passwd $user_name
    expect -exact "Enter new UNIX password: "
    send -- "$pass_word\r"
    expect -exact "\rRetype new UNIX password: "
    send -- "$pass_word\r"
    expect eof
}

 

Please note the fact that the above script assumes that the users testuser, testuser1, testuser2 and testuser3 exists in the system. The line set l [list item1 item2] creates a list with the name of "l". The line foreach user_name $l iterates through each element of the list "l", and sets password for all of them as "sf345234".

 

Lets now see a while loop with expect(basically these conditionals provided by expect is from TCL language. So any conditional that works in tcl should ideally work with expect as well).

 

#!/usr/bin/expect
set pass_word sf345234
set m 0
while {$m<10} {
    spawn passwd "testuser$m"
    expect -exact "Enter new UNIX password: "
    send -- "$pass_word\r"
    expect -exact "\rRetype new UNIX password: "
    send -- "$pass_word\r"
    expect eof
        incr m
}

 

 

In the above example, we create a variable named m with the initial value of 0. Then a while loop is constructed that runs till 9, and during each iteration the value of m is increased by 1(indicated by incr m). This also expects that there are 10 users in the system with the format of testuser0, testuser1, testuser2 and so on till testuser9. The above script should execute as shown below.

 

./password_change.sh
spawn passwd testuser0
Enter new UNIX password:
Retype new UNIX password:
passwd: password updated successfully
spawn passwd testuser1
Enter new UNIX password:
Retype new UNIX password:
passwd: password updated successfully
spawn passwd testuser2
Enter new UNIX password:
Retype new UNIX password:
passwd: password updated successfully

 

 

Lets include one if statement inside the above shown script.

 

#!/usr/bin/expect
set m 0
while {$m<10} {
        set pass_word sf345234
        if { $m == 2 } {
               set pass_word asfjhfajhakasfa234
        }
    spawn passwd "testuser$m"
    expect -exact "Enter new UNIX password: "
    send -- "$pass_word\r"
    expect -exact "\rRetype new UNIX password: "
    send -- "$pass_word\r"
    expect eof
        incr m
}

The if statement we used above is quite self explanatory, if you have used conditionals before. It simply changes the password for the user "testuser2" to a complex one.

Some good use cases of expect can be to automate some of installation scripts provided by proprietary applications, ssh across a series of machines (the password prompt, ssh host key accepting etc can be done using expect), Using command line ftp in an automated way etc. Coupled with autoexpect as we saw above, we can easily automate interactive programs that generally requires a human intervention to proceed.

Rate this article: 
Average: 5 (1 vote)

Add new comment

Plain text

  • No HTML tags allowed.
  • Web page addresses and e-mail addresses turn into links automatically.
  • Lines and paragraphs break automatically.
Type the characters you see in this picture. (verify using audio)
Type the characters you see in the picture above; if you can't read them, submit the form and a new image will be generated. Not case sensitive.