
	There are three new things in this example. First is the concept
of closing the process, second is the concept of using regular
expressions in match patterns, and third is the concept of grabbing
stuff that is in the process's buffer. This last part is like when you
telnet to a host, do ls, and want to know the name of the files returned:


somehost$ ls
thing
thing.gz
core
Mail
mail
somehost$ 

	When you use the expect() function it is possible to grab the
data before the next patter looked for. in this case if you were
looking for "somehost$ " you could get the names of the files returned
in the ls. In the example below the output of the 'id' command is grabbed
for use by the program.

	What this example tries to do is log in to foreign hosts and
grab the user id on each host.


#!/usr/local/bin/perl

use Expect;

@hosts = @ARGV;

# Ssh would be better, rlogin is used here because it is more familiar.
foreach $host (@hosts) {
  $rlogin=Expect->spawn("rlogin $host");

  $rlogin->expect(30,"ssword: ") || die "Never got password prompt on $host\n";

# We got the prompt, so send a password.
  print $rlogin "H4yB3vis\r";

# Now we look for a shell prompt. Notice the use of the regular expression.
# To use a regexp make the previous argument '-re'.
# expect will match on the hostname followed by a %, >, or $ followed by
# whitespace. Notice that the regular expression part is in single quotes.
# This is so that perl won't interpret control characters such as 
# whitespace (\s) for us until it gets in to the pattern matching engine.
# my prompt is "darkwing$ ". Yours is probably different.
# The below expect() call will return 1 if it matches the closed by foreign
# host string or 2 if it matches the regular expression.
# undef is returned if nothing matches.
  $match=$rlogin->expect(30,"closed by foreign host","-re",$host.'[%>$]\s');

  die "Dumped by server\n" if $match == 1;
  die "Never got shell prompt on $host\n" unless $match;

# Ok, so we have a shell prompt. let's give it the 'id' command.
  print $rlogin "id\r";

# Now, we know that because ther terminal will echo "id\r" back to us
# we should grab it so it won't muck with our final output.
# Also, on most terminals if you send a carriage return it will respond
# with a carriage return-newline combination. So we do:
  $rlogin->expect(30,"id\r\n");
# which clears id out of the buffer. Note that I used \r\n in double
# quotes instead of single quotes because I want perl to look for
# a carriage return instead of the literal \r\n. If I had instead done
# $rlogin->expect(30,'-re','id\r\n'); it would work because it gets
# tossed in to a regular expression where \r and \n get evaluated.

# Now when we use expect() to find the next prompt the output of the last
# command will be in the buffer that holds output between expect() calls.
# this output should be 'before' we match.
# I'm going to define what prompt we're looking for ahead of time to
# make the call to expect more readable.
  $prompt = $host.'[%>$]\s';

  ($match_number,$error_if_any,$match_string,$before_match,$after_match) =
  $rlogin->expect(30,'-re',$prompt);

# Yet another way to find out if we had a successful match is to test for
# an error.
  die "Never got prompt after sending 'id' command\n" if $error_if_any;

# And the output of id:
  print "id on $host: $before_match";

# Now, we do a hard close here. We are positively done with rlogin and we
# know that it won't be ending by itself. This would be unlike, say, 
# a command like "tail /etc/passwd" which will exit as soon as it is finished
# sending us its output. For that sort of a command soft_close() would 
# suffice.
# It is important that you close rlogin so that processes don't 
# pile up eating your system resources during further loops through
# hosts.
 $rlogin->hard_close();

# next host
}



