I am bit stuck here I want to ssh in to a machine and then run about 3 commands which are basically setup commands and then i want to return back to my machine with env variables of that machine
like
setup1
setup2
setup3
env > envtext.txt.
return back
All this i have to do in perl
i tried commands like
system("ssh #machine command1 && command 2") doesnt work
is there something like?
system("ssh #machine command1 -cmd command 2 -cmd command 3")
if not than what is the best way to do it
like making a shell script then calling it or i can do it in perl itself without any shell scripts?
code
#!/usr/bin/perl -w
use Net::SSH::Perl;
my $host = "address";
my $user = "name";
my $password = "password";
-- set up a new connection
my $ssh = Net::SSH::Perl->new($host,
debug=>0,
identity_files => ['path to key'],
options=> ["StrictHostKeyChecking no"]
#interactive => yes,
);
-- authenticate
$ssh->login($user,$password);
-- execute the command
my($stdout, $stderr, $exit) = $ssh->cmd("env");
print $stdout;`
error it gives is Permission denied at ssh.pl line 25
Thank you
I think your question is about SSHing to a single remote host and running multiple commands there. If that's true, then you need to pack your multiple commands up into a single command line that the remote shell can execute. The easiest way to do this is to use the list form of system, and pass the command line as a single parameter:
system "ssh", "machine", "setup1; setup2; setup3";
On to the second part of your question: You want to get data back from the remote side. For that, you'll want your program to read SSH's output rather than using system. For this, you can use:
open my $FH, "-|", "ssh", "machine", "setup1; setup2; setup3; env";
my #lines_from_ssh = <$FH>;
close $FH;
If you also need to send input to the remote side, look into IPC::Open2. If you need to capture both stdout and stderr, see IPC::Open3.
What you can do :
system("ssh $_ command1 -cmd command 2 -cmd command 3") for #machines;
Another Pure Perl solution is to use Net::OpenSSH
Related
I am trying to run a couple of commands in putty from perl. Right now my code gets me into putty but I am unsure of how to execute commands from there.
my $PUTTY = 'C:\Users\Desktop\putty.exe';
my $dacPutty = "$PUTTY, -ssh username#server - l username -pw password";
system ($dacPutty);
system (ls);
use plink instead. ( http://the.earth.li/~sgtatham/putty/0.60/htmldoc/Chapter7.html )
plink is in the same directory as putty.
Usually in Perl it's better to use a Perl module, where one exists, than to shell out.
Using a module is more portable, and often gives you more control. system introduces many opportunities for security bugs, so it's good to avoid it where possible.
In this case, use Net::SSH::Perl http://search.cpan.org/~turnstep/Net-SSH-Perl-1.38/lib/Net/SSH/Perl.pm
Once installed:
use Net::SSH::Perl;
my $ssh = Net::SSH::Perl->new("host1");
$ssh->login("user1", "pass1");
$ssh->cmd("cd /some/dir");
$ssh->cmd("foo");
For reliability, you should actually check the result of each cmd:
my ($stdout, $stderr, $exit) = $ssh->cmd("cd /some/dir");
unless ($exit == 0) {
// Handle failed cd
}
The document notes that with SSH-1, each cmd reconnects, so the above would not work -- you would cd in one shell, then foo in a completely new shell. If you have to use SSH-1, then you'd need to do:
$ssh->cmd("cd /some/dir; foo");
(And you can use a similar trick even if you're making a system call to plink)
How can I set the remote server shell to bash through the perl telnet?
My code is below:
$telnet = Net::Telnet->new(Timeout=>90,Errmode=>'die');
$telnet->open($ipAddress);
$telnet->login($username,$password);
$telnet->waitfor('/$/');
$telnet->print("exec bash");
print "after bash";
print $telnet->cmd("ls -lrt");
print $telnet->cmd("cd $homePath");
In the above code, after the exec bash statement, none of the commands are getting executed. I need to set the remote shell as bash because some of the processes I need to run after this lines require env settings.
Please let me know how can I do the same.
Your regex to wait for the command prompt is wrong
$telnet->waitfor('/$/');
Try
$telnet->waitfor('/\$ $/');
Even better, see the first example in the Net::Telnet 3.04 doc:
my $host = 'your_destination_host_here';
my $user = 'your_username_here';
my $passwd = 'your_password_here';
my ($t, #output);
## Create a Net::Telnet object.
use Net::Telnet ();
$t = new Net::Telnet (Timeout => 10);
## Connect and login.
$t->open($host);
$t->waitfor('/login: ?$/i');
$t->print($user);
$t->waitfor('/password: ?$/i');
$t->print($passwd);
## Switch to a known shell, using a known prompt.
$t->prompt('/<xPROMPTx> $/');
$t->errmode("return");
$t->cmd("exec /usr/bin/env 'PS1=<xPROMPTx> ' /bin/sh -i")
or die "login failed to remote host $host";
$t->errmode("die");
## Now you can do cmd() to your heart's content.
#output = $t->cmd("uname -a");
print #output;
I use a Perl script to configure and spawn a compiled program, that needs a subshell configured a certain way, so I use $returncode = system("ulimit -s unlimited; sg ourgroup 'MyExecutable.exe'");
I want to capture and parse the STDOUT from that, but I need it forked, so that the output can be checked while the job is still running. This question comes close:
How can I send Perl output to a both STDOUT and a variable? The highest-rated answer describes a function called backtick() that creates a child process, captures STDOUT, and runs a command in it with exec().
But the calls I have require multiple lines to configure the shell. One solution would be to create a disposable shell script:
#disposable.sh
#!/bin/sh
ulimit -s unlimited
sg ourgroup 'MyExecutable.exe'
I could then get what I need either with backtick(disposable.sh) or open(PROCESS,'disposable.sh|').
But I'd really rather not make a scratch file for this. system() happily accepts multi-line command strings. How can I get exec() or open() to do the same?
If you want to use shell's power (that includes loops, variables, but also multiple command execution), you have to invoke the shell (open(..., 'xxx|') doesn't do that).
You can pass your shell script to the shell with the -c option of the shell (another possibility would be to pipe the commands to the shell, but that's more difficult IMHO).
That means calling the backtick function from the other answer like this:
backtick("sh", "-c", "ulimit -s unlimited; sg ourgroup 'MyExecutable.exe'");
The system tee with backticks will do this, no?
my $output = `(ulimit -s unlimited; sg ourgroup 'MyExecutable.exe') | tee /dev/tty`;
or modify Alnitak's backticks (so it does use a subshell)?
my $cmd = "ulimit -s unlimiited ; sg ourgroup 'MyExecutable.exe'";
my $pid = open(CMD, "($cmd) |");
my $output;
while (<CMD>) {
print STDOUT $_;
$output .= $_;
}
close CMD;
Expect should be used as you are interacting with your program: http://metacpan.org/pod/Expect
Assuming /bin/bash on your *nix matches something like bash-3.2$ the below program can be used to launch number of commands using $exp->send on bash console and output from each command can then be parsed for further actions.
#!/usr/bin/perl
use Expect;
my $command="/bin/bash";
my #parameters;
my $exp= new Expect;
$exp->raw_pty(1);
$exp->spawn($command);
$exp->expect(5, '-re', 'bash.*$');
$exp->send("who \n");
$exp->expect(10, '-re', 'bash.*$');
my #output = $exp->before();
print "Output of who command is #output \n";
$exp->send("ls -lt \n");
$exp->expect(10, '-re', 'bash.*$');
my #output = $exp->before();
print "Output of ls command is #output \n";
I am new to this module. I tried a sample program and it worked fine. But, now I would like to how do I execute multiple commands in this program :
use Net::SSH::Perl;
my $hostname = "<<hostname>>";
my $username = "<<username>>";
my $password = "<<password>>";
my $cmd = 'mkdir script; cd script';
my $ssh = Net::SSH::Perl->new("$hostname", debug=>0);
$ssh->login("$username","$password");
my ($stdout,$stderr,$exit) = $ssh->cmd("$cmd");
print $stdout;
You can just call cmd repeatly.
The problem you are facing may be that every command is run in a different shell and commands that are run for their side effects as cd or export become useless.
As a work around you can prefix all the commands with the cd $dir command. For instance:
my ($stdout1, $stderr1, $exit1) = $ssh->cmd("cd /$dir && $cmd1");
my ($stdout2, $stderr2, $exit2) = $ssh->cmd("cd /$dir && $cmd2");
...
Another option is to run a shell on the remote host and talk to it, but this is more difficult and error prone.
Finally, Net::SSH::Perl is old and unmaintained, nowadays, Net::SSH2 or Net::OpenSSH are usually better options.
I have to connect to a remote machine via SSH executed through Expect module. I have to access the STDERR/STDOUT separately if possible and look at the output. I can redirect the output of the script e.g.
$command = "ssh <script> 2>/tmp/stderr.output"
$exp = Expect->spawn($command) or die "Cannot spawn\n";;
my #command1= $exp->expect(5);
but then I have to remotely connect again to check stderr.output.
Is there a way that expect returns the STDERR/STDOUT separately.
You might want to consider using Net::OpenSSH which provides a capture2 method:
($output, $errput) = $ssh->capture2(\%opts, #cmd)
captures the output sent to both stdout and stderr by #cmd on the remote machine.