Expect

From Notes_Wiki

Home > Shell scripting > Using expect

We can use expect to supply input to programs when simple redirection is not sufficient. The important expect commands are:

  1. spawn
  2. expect
  3. send
  4. interact


spawn

spawn command is followed by shell command. That shell command is executed and then we can use 'expect' to read from that commands output and use 'send' to send input to given program.


expect

expect looks for given pattern anywhere in input. It need not be last pattern. Anything after pattern remains in expect buffer and can be printed using 'send_user "$expect_out(buffer)"' to user. expect takes on string as argument and only after that string is matched script will proceed. We can create if/then type of cases using expect by specifying multiple patterns in following way:

expect {
"hi" { send "You said hi\r"}
"hello" { send "Hello yourself\r"}
"bye" { send "That was unexpected\r"}
}

Although normally all commands must end in a line. Because of use of '{' all lines till matching '}' are read and then treated as one single command. This expect will send different output to program (Note send is used to send values to program, send_user to send output to user) based on whether program output contains hi or hello or bye.

Note:

  • We can use exp_continue to continue with same expect so that other cases of same expect can match based on left input. This can be useful in cases like ssh where if yes/no is found then after sending "yes\r" we would like expect to continue for password prompt
  • expect times out in 10 seconds or so. We can defer timeout by asking script to sleep or by changing timeout value using 'set timeout <new_value>'
  • Instead of specifying glob patterns (Wildcard patterns) we can use -re option and specify regular expression to match. When we use regular expressions expect can also extract substrings for back-reference for later use.
  • From start of input to expect (output of program) to end of current pattern match is stored in expect_out(buffer), which we can print to user using send_user "$expect_out(buffer)". We can also access substrings matched when using regular expressions with help of expect_out([1-9], string). expect_out(0, string) has entire regular expression match.
  • We can use keywords eof and timeout to take care of end of file and timeout cases when using expect


send

Spawned program can be fed input using send. We should end send with "\r" and not with "\n" if user normally presses return key after typing.


interact

Gives control of current spawned process to user. Everything from this point onwards typed by user will go to program and program output is displayed on screen. Hence spawned process behaves as if we have run it on shell by user directly.


Expect examples

HTTP Request

Following expect scripts connects to a webserver using and sends a HTTP request. Then it searches for something which is not there and prints entire expect buffer.

#!/usr/bin/expect -f
spawn telnet intranet.iiit.ac.in 80
expect "Escape character is " 
send "GET HTTP://intranet.iiit.ac.in/ HTTP/1.0\r"
send "Host: intranet.iiit.ac.in\r"
send "\r"
expect "anything that will surely not be there on page"
send_user "$expect_out(buffer)"

Note that this technique can be extended to supply POST values using expect


Supplying ssh/scp passwords

The below code after suitably replacing <password> can be used to ssh to mirage server and run "ls -a" command. We can close the connection by using close to close input/ouput streams which will cause ssh to end or we can also send "exit" command to close ssh connection.

#!/usr/bin/expect -f
spawn ssh saurabh.barjatiya@example.com
expect "password:"
send "<password>\r"
expect "saurabh.barjatiya@mirage"
send "ls -a\r"
set timeout 1
expect "Not there"
send_user "$expect_out(buffer)"
close
#send "exit\r"
#expect "Not there"
#send_user "$expect_out(buffer)"

Using sshpass might be easier then trying to do this via expect in this particular use-case.


SSH login

Following script will ssh to mirage server and give control to user. This is useful if we want script to just logon to server and later on we want control of the ssh connection.

#!/usr/bin/expect -f
spawn ssh saurabh.barjatiya@mirage.iiit.ac.in
expect "password:"
send "<password>\r"
expect "saurabh.barjatiya@mirage"
interact 


rsync of very large folders

Following script was used to rsync very large folders that consisted of large VM images using expect from one machine to another

#!/usr/bin/expect -f
spawn rsync -vazS --progress --partial root@10.3.3.48:/mnt/data1/saurabh_do_not_delete/ /mnt/data1/saurabh_do_not_delete/
set timeout -1
sleep 3
expect {
		yes/no {
                send "yes\r"
                exp_continue
        }
        password: {
                send "iiit123\r"
                exp_continue
        }
        denied {
                send "iiit123\r"
                exp_continue
        }
	eof {
		exit 0
	}
}
wait
exit 0



Home > Shell scripting > Using expect