Saturday, January 12, 2008

Taking a Look At Expect on Linux and Unix

Hey There,

Another lazy Saturday (actually, I'm just finishing a fun 7pm to 5am shift), so I thought I'd kick it off by touching on a subject we've never addressed in any of our Unix or Linux shell scripts. I expect you know what I'm talking about if you've read the title (There was almost no way around making a bad joke there ;)

Expect is a great tool to incorporate in a shell script when you need to fake some form of human interaction. For instance, if you need to do some complex work over Telnet or SSH. We'll get into more complicated scripts later, and tailor them for both Linux and Unix. Today, I snapped out a quick Expect script to introduce the language. If you've been around long enough (or had the pleasure) to use chat, Expect is probably going to seem fairly familiar. Its name explains the core functionality. It "expects" some sort of input (That you determine or decide) and reacts on it when it finds it (which action you also dictate).

For today, just take a look at this script, and you can see what I mean. The language, itself, is an extension of the TCL language, which makes it easy to program in all on its own (and get very creative with ;) Most of the commands are self-explanatory, and you'll note that lines like:

expect -re "220 .*\r\n"

are instructions to the Expect shell telling it to react when it recognizes that particular regular expression (as denoted with the "-re" flag). Basically, it's going to wait for a line to pass into its buffer that reads "220 whatever" ending with a carriage return and then react on that.

Another interesting thing, that ties into the above, and should be a mainstay of Unix and Linux Expect scripting, is the "timeout" variable. This is set in the script at the top:

set timeout 10

but can be set multiple times in the script and (given the default value I've chosen) can be left out if you want to go with the standard 10 second timeout. This directive tells Expect that, when it's expecting something, if it doesn't find it in 10 seconds, it should move on to the next line.

The little script below simply connects to a server's SMTP port and attempts to issue the VRFY command to determine if a user name is good or not. Now, most servers won't respond to that command, due to growing security problems with its use (or misuse ;), but this is just an example. And it may just work.

The last line ("interact") tells Expect it's time for you the user to do your thing. You can escape out of this by ending the currently spawned process (the SMTP prompt). You can just type "quit", or ctl-C, and the remainder of script will process. In this case, you'll get a shell prompt, as the script ends with that line :)


Creative Commons License

This work is licensed under a
Creative Commons Attribution-Noncommercial-Share Alike 3.0 United States License


# lame example script. Connect
# to a mail server and see if we
# can verify usernames
# 2008 - Mike Golvach -
# Creative Commons Attribution-Noncommercial-Share Alike 3.0 United States License

set timeout 10
send_user "Checking...\n"
log_user 0
set wordfile $argv
eval spawn telnet localhost 25
expect -re "220 .*\r\n"
set wf [open $wordfile]
while {[gets $wf buf]!=-1} {
set word $buf
send_user "$word... "
send "VRFY $word\r"
expect {
-re "2.. .*\r\n" {
send_user "Good!\n"
-re "5.. .*\r\n" {
send_user "Bad!\n"