Link to home
Start Free TrialLog in
Avatar of SapphireGirl
SapphireGirlFlag for United States of America

asked on

How do I use Expect to execute a system command on a remote server in Perl

I have used the backtick  but I would like to use the Expect methods.

Does anyone have a good example of using Expect in a Perl function?

Thank you.
Avatar of Adam314
Adam314

There is an Expect module for perl.  It is documented, and has examples:
    http://search.cpan.org/~rgiersig/Expect-1.21/Expect.pod

Is this what you are talking about?  
Avatar of SapphireGirl

ASKER

Ok, I got my TestExpect method to work to STDOUT but it does not correctly write to my File.  This is what I did.  Please give my your feedback on whether or not this is the best way to do this.
I basically want a reusable function that I can send any command to when rsh(ing) to a remote server.

sub TestExpect {
  my ($self, $command) = @_;

  my $exp = new Expect;
  if ($PrintReport) {
     $exp->exp_init($self->tangoReportFile);
  }

  $exp->raw_pty(1);
  $exp->spawn($command)
    or die "Cannot spawn $command: $!\n";

# send some string there:
  $exp->send($command);


  if ($PrintReport) {
# or, for the filehandle mindset:
  print $exp $command;


  }
$exp->soft_close();

}
I'm not sure what you are trying to do... but this:
    $exp->spawn($command) or die "Cannot spawn $command: $!\n";
    # send some string there:
    $exp->send($command);

Will try to start $command on this server, then send $command to that process.  Is this really what you intended?

What are you trying to do?  If you aren't capturing any of the output, maybe Expect isn't really what you need.
Ok, I set the $PrintReport flag to be 1 and the program chokes with the error

Attempt to bless into a reference at /usr/lib/perl5/vendor_perl/5.8.6/Expect.pm line 182.

I must not be using the $exp->exp_init() method correctly.
I passed it an open FH.

I would like to capture the output in 2 ways.
1.  Just STDOUT (printing to the screen) or
2.  Write it to a Report File.
I think I want to be using the Expect Methods because I could be running this TestExpect method in a loop say 64 or 128 times.

Does that make sense.  I did not want to use backticks and capture the response.
Why did you not want to use backticks?  Expect is good if you need to look for some particular output, and provide input based on that.  If you just want to capture all of the output, backticks are fine.  If the output is to large to store in a variable all at once (which is what happens with backticks), you might use open with "|", and read/process 1 line at a time.  If you need to read from and write to the process, open2 or open3 might be good.

What are you trying to do?
Here is what I am trying to do.
1.  rsh into a remote server and check the disk space on 4 of the mounts.
2.  If the ds is greater than 95% on these mounts, I need to email the users of the largest files on that server.
I can hack this out but this is how I want to solve this programming problem.

I want to automate all of this in an elegant solution.
An elegant solution to me is a solution in which I can perform any command line system call, whether it be calling scripts, checking disk space, etc in a perl class.
That is why I am trying  to write the TestExecute method to be a very general function that can be used not only for a system df call but maybe some other systems calls in the future.
This is why I am passing in the Command.
So this time it will be checking disk space and next time I will (lets say) push files on a set of machines.
I did not want to use the backtick because I have read that it could be unreliable.

It seemed like using the Expect functions would be a good way to solve a general problem.

Does that make sense.


The backticks are not unreliable if you do not need to provide input to your command.  If, from the command prompt, you can run rsh, and not be asked anything (meaning, the program just runs, and you get your output), then backticks will be just fine.

There are also several perl modules to help you make an ssh connection, and run a program.  You might want to consider one of them.  For a single command, the Net::SSH module makes sense.

If you already have keys setup, and you just want to execute a command, you can use this:
use Net::SSH 'ssh';

my $output = ssh('user@host', 'df');
#Parse $output to determine free disk space,  or use a different command
Here is my problem though,  I do not know how to parse thru a directory structure using a back tick command.

Ex.  I want to get to machinea and then iteratively go thru the /project directory and all of its sub directories to get a total for lets say userA, userB, and userC.

I don't think I can do it with a ` ` back tick command without having the rsh into the machinea several times.
This would add lots of time and complications if the machine(s) were to go down during the time this script is running.  These methods should be able to thru about 100 machines, each with 4 different mounts, with hundreds of projects on them.  I need to find an solution that is going to be robust and quick.  (Duh, that is what every programmer wants) :0
ASKER CERTIFIED SOLUTION
Avatar of Adam314
Adam314

Link to home
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
Start Free Trial
Thank you Adam,  I will use the back tick, capture the output to a file then parse the file to do what I need to do.  When would you use Expect though?
For SSH - I wouldn't, as there are modules specifically designed for SSH that I think are easier to use.
In general - if I had an external program with which I needed to interact.