use strict; use warnings; use Net::SSH2; use Term::ReadLine; my $host = 'hostname'; my $user = 'username'; my $pass = 'password'; my $ssh2 = Net::SSH2->new(); if ($ssh2->connect($host, 22)) { if ($ssh2->auth_password($user, $pass)) { my $chan = $ssh2->channel(); $chan->blocking(0); # Needed on Windows $chan->shell(); binmode($chan) # Seems to take care of both Unix SSH and Cisco servers # Also set binmode in Net::Telnet::Cisco (\n vs \r\n) # Needed to "clear", flush() doesn't seem to work # Otherwise, first command does not work chan_read($chan); # START: Interactive Mode my $prompt = "ssh> "; my $ssh = Term::ReadLine->new("SSH"); $ssh->ornaments(0); # Main loop. This is inspired from the POD page of Term::Readline. while (defined (my $cmd = $ssh->readline($prompt))) { chomp $cmd; # nothing if ($cmd =~ /^\s*$/) { next } # exit if ($cmd =~ /^\s*exit\s*$/) { last } cmd($chan, $cmd) } $chan->close } else { warn "Authentication failed\n" } } else { warn "Unable to connect to host $host: $!\n" } sub cmd { my ($chan, $cmd) = @_; chomp $cmd; $chan->write("$cmd\n"); select(undef,undef,undef,0.2); # or sleep 1 my $ret = chan_read($chan, $cmd); print $ret } sub chan_read { my ($chan, $cmd) = @_; # need actual polling method rather than select or sleep to wait for a bit # example from the Net::SSH2 code, but doesn't seem to work: # # my @poll = ({handle => $chan, events => 'in'}); # if($ssh2->poll(250, \@poll) && $poll[0]->{revents}->{in}) { # print "HERE\n" # } # # or select(): # # my ($rin, $rout, $ein, $eout) = ('', '', '', ''); # vec($rin, $chan, 1) = 1; # tried $ssh2 and $chan, both "worked" # # should be: fileno($var) # if (select($rout=$rin, undef, $eout=$ein, 5000)) { # print $buf while defined ($len = $chan->read($buf,512)) # } my $DONE = 0; my $buffer; # Read until $DONE while (1) { last if $DONE; my $buf; # Read chunk while (defined (my $len = $chan->read($buf,512))) { # Found $PROMPT - then $DONE if ($buf =~ $PROMPT) { $buf =~ s/$PROMPT//; $DONE++; } $buffer .= $buf; } } # Remove $cmd from first line so no echo back if ((defined $cmd) and ($buffer =~ $cmd)) { $buffer =~ s/^$cmd\r\n//; } return $buffer }