Skip to content

Instantly share code, notes, and snippets.

@marshyon
Created July 29, 2012 13:51
Show Gist options
  • Save marshyon/3198938 to your computer and use it in GitHub Desktop.
Save marshyon/3198938 to your computer and use it in GitHub Desktop.
test and demonstrate the use of Net::SSH::Expect Perl module to connect via SSH using key authentication, to known and unknown hosts, running commands and processing captured standard output from those commands
#!/usr/bin/env perl
use warnings;
use strict;
use Date::Parse;
use Net::SSH::Expect;
use POSIX qw(strftime);
# set to a known host on your network
# that has not been ssh shell connected
# to by this user before
my $known_host = "some_server_we_know";
# invoke a Net::SSH::Expect object
my $ssh = Net::SSH::Expect->new (
host => "localhost",
user => 'marshyon',
raw_pty => 1
);
# as we have already set up an SSH key pair and
# loaded it with 'ssh-add' and tested the connection
# manually, we need no password to connect to the
# target server ....
$ssh->run_ssh() or die "SSH process couldn't start: $!";
# we over-ride the current console prompt, likely set by
# .bashrc or system wide bash or profile with one that we
# know has no 'escape characters' ( e.g. colors ) and that
# we can use later to pattern match returned output
my $set_promt_cmd = q(PS1='console:\h \$ ');
$ssh->exec($set_promt_cmd);
# get the hosname of the host we are connected to
my $hostname = $ssh->exec("hostname");
$hostname=~ m{(.+?)\nconsole:}msx;
# using the custom prompt we set earlier, the hostname
# can be accurately extracted from captured stdout
print "hostname is [$1]\n";
# now we can ssh to a server that exists but we
# have not visited before
my $ssh_session = $ssh->exec("ssh $known_host");
# testing the returned output we can see that this is the
# case and respond to not accept and record the key from
# this connection
if( $ssh_session =~ m{Are you sure you want to continue}i ) {
print "we have not seen this one before,....\n";
$ssh->exec("no");
}
# next we try to connect to a server that does not
# exist or is otherwise off line
$ssh_session = $ssh->exec("ssh no_server_anywhere");
if( $ssh_session =~ m{Could not}i ) {
print ">>>\n$ssh_session\n";
print "this one seems like its a gonner...\n";
}
# on the current server connection we now run a command to
# list the current directory
# nb: ls will 'colourise' it's output unless we use the switch
# '--color=never' - colours will contain escape characters
# that will goose some pattern matching from working
# properly
my $listing_cmd = 'ls --color=never -al';
my $listing = $ssh->exec($listing_cmd);
$listing =~ m{(.+)\nconsole:}msx;
print ">>\n$1\n.................\n";
# lastly, lets do something useful with the listing we just
# got back, namely extract file name, file date when last modified
# and the size of each file
# file
my @file_listing = split(/\n/, $listing);
foreach my $file_list (@file_listing) {
# here is an example of what we are trying to match ....
# -rw------- 1 marshyon marshyon 2089 Jul 29 13:57 .bash_history
# here is the regex in an 'if' with comments ( the x switch in ... match {} msx ..
# lets us add comments to the regular expression ) ....
if( $file_list =~ m{
\S+ \s+ \d+ \s+ # non space(s), space(s), digit(s), space(s)
marshyon \s+ # literal string, space(s)
marshyon \s+ # literal string, space(s),
( \d+ ) \s+ # capture digit(s) into $1 followed by space(s)
(.+?) \s+ # one or more characters non greedy captured to $2, space(s)
(\S+) $ # non space(s) captured to $3 to end of line
}msx ) {
my ($size, $date_str, $file) = ($1, $2, $3);
# using Date::Parse modules function, parse date string
my $epoch = str2time($date_str);
my $date_formatted = strftime "%Y-%m-%d %H:%M", localtime;
print "size[$size] epoch[$epoch] date_formatted[$date_formatted] file[$file]\n";
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment