Expect scripting

Expect scripting language is used to feed input automatically to an interactive program. It is easy to learn compared to other scripting languages. Using expect script system admins and developers can automate redundant tasks easily. It works by expecting specific strings, and sending or responding strings accordingly.

Following three expect commands are used when automating any interactive processes.

  • send – to send the strings to the process
  • expect – wait for the specific string from the process
  • spawn – to start the command

Make sure to install expect packages on your system, as it does not get installed by default. Once installed, you’ll see the expect interpreter as “/usr/bin/expect”. Generally, expect script files has .exp as extensions.

1. “Hello World” Example

The following expect script is expecting the specific string “hello”. When it finds it (after user enters it), “world” string will be send as response.

#!/usr/bin/expect
expect "hello"
send "world"

#Save this file as hello.exp
#Change access of this file 
chmod a+x hello.exp
#Run as
./hello.exp

2. Timeout On Expect String

By default, the expect timeout is 10 seconds. If you don’t enter anything for the expect command, it times out in 20 seconds. You can also change the timeout as shown below.

#!/usr/bin/expect
set timeout 10
expect "hello"
send "world"

3. Automate User Processes With Expect

With the help of expect, you can automate the user processes and get the expected output. For example, you might use this to simplify the project testing process by writing scripts for the test cases.

The below example does the addition program automation.

#!/usr/bin/expect
set timeout 20

spawn "./addition.pl"

expect "Enter the number1 :" 
 { 
   send "12\r" 
  }
expect "Enter the number2 :" 
  { 
    send "23\r" 
  }

interact

Execute this as shown below.

$ ./user_proc.exp
spawn ./addition.pl
Enter the number1 : 12
Enter the number2 : 23
Result : 35

In case, if you have written the code without interact command, then the script would exit immediately after sending the string “23\r”. Interact command does the control, hands over the job to the addition process, and produces the expected result.

4. Match and No Match Contents in $expect_out Variables

On the successful matching of string expect returns, but before that it stores the matched string in $expect_out(0,string). The string that are received prior plus the matched string are stored in $expect_out(buffer). The below example shows you the value of these two variable on match.

#!/usr/bin/expect

set timeout 20

spawn "./hello.pl"

expect "hello"

# String before match + String matched
send "no match : <$expect_out(buffer)> \n"

# String matched
send "match :  <$expect_out(0,string)>\n"

interact

The hello.pl program just prints only two lines as shown below.

#!/usr/bin/perl

print "Perl program\n";
print "hello world\n";

Execute it as shown below.

$ ./match.exp
spawn ./hello.pl
Perl program
hello world
no match :  <Perl program

hello>
match :  <hello>

5. Automate SU login into Other User Accounts

Expect allows you to pass the password for the Linux login account from the program, instead of entering the password on the terminal. In the below program, su login is automated to login into desired accounts.

#!/usr/bin/expect

set timeout 20

set user [lindex $argv 0]
set password [lindex $argv 1]

spawn su $user
expect "Password:"
send "$password\r";

interact

Execute the above expect program as shown below.

ji@verma $ ./su.exp guest guest
spawn su guest
Password:
guest@verma $

After running the above script, it logged into the guest user account from ji user account.

6. SSH Login into Another Machine

The example expect program shown below automates the ssh login from one machine to another machine.

#!/usr/bin/expect

set timeout 20

set ip [lindex $argv 0]
set user [lindex $argv 1]
set password [lindex $argv 2]

spawn ssh "$user\@$ip"
expect "Password:"
send "$password\r";

interact

Execute the above expect program as shown below.

guest@anukul $ ./ssh.exp 192.168.1.2 root password
spawn ssh root@192.168.1.2
Password:
Last login: Sat Jan 9 04:01:35 2017 from ji.creative.com
root@verma #

7. Define Expect Variables – set command

In expect, you can set the variable values using set command as shown below,

# To set the variable with numeric values
set var1 10

# To set the variable with string literal
set name "ji"

# To set the variable value which includes output of another command
set proc_id "process id : [pid]"

8. Expect Expressions – expr command

To evaluate the expressions, use the expr command, which executes the given expression and returns the result. Expect expressions are similar to the C expressions. Some of the valid expressions are listed below.

# To add two simple numerical values
set sum "[expr 1 + 1]"

# To multiple the value of variables
set mul "[expr $sum * $sum]"

# To evaluate conditions and returns 1 or 0 to indicate success or failure accordingly.
set ret "[expr (1+1) == 2]"

# Conditions may contain the command return values.
set ret [expr [pid] == 0]

9. Expect Conditional Expressions – If command

If command is used for conditional flow of execution of statements as shown in the example below.

if { $count < 0} {
    puts "True : $count\n";
} else {
    puts "False : $count\n";
}

Just like any other programming language, you can use the elseif command in expect as shown below.

if { $count < 0} {
    puts "Success Condition1 : $count\n";
} elseif { $count == 0 } {
    puts "Success Condition2 : $count\n";
} else {
    puts "False : $count\n";
}

10. Expect Looping Constructs

As we know, for loop is used to do repeated execution of expression until certain condition.

General for loop construct :

for {initialization} {conditions} {incrementation or decrementation} {
...
}

Expect for loop example :

for {set i 1} {$i < $no} {incr i 1} {
 set $total [expr $total * $i ]
}
puts "$total";

Note: You should place the loop open brace in the same line as it contains “for” keyword.

Expect While Loop Examples:

set count 5;
while {$count > 0 } {
puts "count : $count\n";
set count [expr $count-1];
}

11. Execute expect script from the command line using -c option

expect also also allows you to execute it directly in the command line using -c option as shown below.

$ expect -c 'expect "\n" {send "pressed enter\n"}

pressed enter
$

Once you run the above script, it waits for the newline(\n) and upon pressing the enter key, it will print the message “pressed enter” and exits.

12. Execute expect script interactively using -i option

Expect script can run interactively by reading commands from the standard input using -i option as shown below.

$ expect -i arg1 arg2 arg3
expect1.1>set argv
arg1 arg2 arg3
expect1.2>

Normally when you run the above expect command without -i option, it would treat the arg1 as script filename, so the -i option makes the argument list as uninterrupted.

This option is useful when you run the expect script with the -c flag. Because by default expect runs interactively.

13. Print debug messages while executing expect script

You might enable the diagnostics messages to be printed when you run the code with -d option as shown below.

$ cat sample.exp
# !/usr/bin/expect -f
expect "\n";
send "pressed enter";

$ expect -d sample.exp
expect version 5.43.0
argv[0] = expect  argv[1] = -d  argv[2] = sample.exp
set argc 0
set argv0 "sample.exp"
set argv ""
executing commands from command file sample.exp

expect: does "" (spawn_id exp0) match glob pattern "\n"? no

expect: does "\n" (spawn_id exp0) match glob pattern "\n"? yes
expect: set expect_out(0,string) "\n"
expect: set expect_out(spawn_id) "exp0"
expect: set expect_out(buffer) "\n"
send: sending "pressed enter" to { exp0 pressed enter}

14. Enable expect debugger using -D

-D option is used to enable the debugger and it just takes the boolean value as an argument. This will indicate whether the debugger has to be started or just initialize it and use it at the later time.

$ expect -D 1 script

The options before the left of the -D option will get processed before the debugger. Then the remaining commands will get executed after starting the debugger.

$ expect -c 'set timeout 10' -D 1 -c 'set a 1'
1: set a 1
dbg1.0>

15. Execute expect script line by line

Normally expect reads the entire script into the memory before executing it. -b option makes the expect to read the script one line at a time. This could be useful when you have not written the completely by that time and expect starts executing it and thus it avoids writing of temporary file.

$ expect -b

 

Advertisements

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s