A Perl5 Script Copy File Via SSH

清华大佬耗费三个月吐血整理的几百G的资源,免费分享!....>>>

#!/usr/bin/env perl

use utf8;
use strict;
use warnings;
use 5.10.0;

use File::Copy qw/copy/;
use File::stat;
use Net::SFTP;
use Getopt::Long;
use File::Basename;

use constant {
	OK => 1,
};


#	--remote
#	--inversion
#	--cplist=file

my $help = 0;
my $remote = 0;
my $mode = "";
my $cplist = "";
my $kpath = '.'; ##need path
my $vpath = '.';
my %ssh = (
	'ip' 	=> "192.168.8.73",
	'user'	=> "root",
	'pass'	=> "",
	);

Getopt::Long::Configure ("bundling_override");

my $ret = GetOptions(	'remote|r' 		=> \$remote,			#use ssh or local?
						'cplist|c:s' 	=> \$cplist,			#copy file list
						'kpath|k:s'		=> \$kpath,			#cplist key's path
						'vpath|v:s'		=> \$vpath,			#cplits value's path
						'mode|m=s'		=> \$mode,				#mode = k || v  !! k = k | left | up v = v | right | down
						'ip|h:s'		=> \$ssh{'ip'},
						'user|u:s'		=> \$ssh{'user'},
						'pass|p:s'		=> \$ssh{'pass'},
						'help|?',		=> \$help,
	);

if ($help) {
	say 'copy.pl --cplist | -c "copy list file config"';
	say '--mode | -m = [k | v | up | down | right | left] ';
	say '[--kpath | -k = ""] [--vpath | -v = ""]';
	say '[--remote | -r] [--ip | -h = ""] [--user | -u = ""] [--pass | -p = ""]';
	say '[--help | ?]';
	exit;
}

#printOptions();

errExit('Argument parser error') if (!$ret);

if (!defined($mode = checkMode($mode))){
	errExit("Mode shoud be k or v");
}
my %list = ();

if ($cplist eq "") {
	errExit("Need cplist.");
} else {
	%list = readList($cplist);
}

if ($remote) {
	if (! &isIp($ssh{'ip'})) {
		errExit('You lost host ip >_<');
	}
	goto GOTO_LABEL_REMOTE;
} else {
	goto GOTO_LABEL_LOCAL;
}

my $sftp;

GOTO_LABEL_REMOTE:
	$sftp = Net::SFTP->new($ssh{'ip'}, user => $ssh{'user'}, password => $ssh{'pass'});

	if (! $sftp) {
		die "Can not login $ssh{'user'}\@$ssh{'ip'}!";
	} else {
		say "Connect to $ssh{'ip'}:22 with $ssh{'ip'} ok";
	}

	sshCopyList($mode);
exit;

GOTO_LABEL_LOCAL:
	localCopyList($mode);
exit;
#############################################################
#ssh
sub sshCopyList {
	my $d = shift @_;
	
	my @ks = keys(%list);
	
	if ($d) { ##1 -> upload
		foreach (@ks) {
			upload_ssh_ssh($sftp, $kpath . $_, $vpath . $list{$_});
		}
	} else {
		foreach (@ks) {
			download_ssh_ssh($sftp, $kpath . $_, $vpath . $list{$_});
		}
	}
}

sub upload_ssh_ssh {
	my ($s, $k, $v) = @_;
	
	say 'x' x 100;
	say "<1 upload $k -----> $v";
	
	###$k -> $v
	
	if (localExist(2, $k)) {
		sshUnlink($s, 2, $v);
		sshUpload($s, 3, $k, $v);
	}
	
	say '';
}

sub download_ssh_ssh {
	my ($s, $k, $v, $d) = @_;
	
	say 'x' x 100;
	say "<1 download $k -----> $v";
	
	if (sshExist($s, 2, $k)) {
		localUnlink(2, $v);
		sshDownload($s, 3, $k, $v);
	}
	
	say '';
}

#############################################################
#local
sub localCopyList {
	my $d = shift @_;
	
	my @ks = keys(%list);
	
	if ($d) { ## 1 --> left -> right
		foreach (@ks) {
			copy_local_local($kpath . $_, $vpath . $list{$_});
		}
	} else {
		foreach (@ks) {
			copy_local_local($vpath . $list{$_}, $kpath . $_);
		}
	}
}

sub copy_local_local {
	my ($k, $v) = @_;
	
	say 'x' x 100;
	say "<1 copy $k -----> $v";
	
	if (localExist(2, $k)) {
		localUnlink(2, $v);
		localCopy(3, $k, $v);
	}
	say '';
}

#############################################################
# other sub part			
##

sub sshDownload {
	my ($sftp, $index, $src, $dest) = @_;
	
	say "<$index download $src -> $dest";
	
	if (defined($sftp)) {
        my $ret = $sftp->get($src, $dest);
        
        return OK if $ret;
	}
	
	return !OK;
}

sub sshUpload {
    my ($sftp, $index, $src, $dest) = @_;
    
    say "<$index upload $src -> $dest";
    
    if (defined($sftp)) {
        my $ret = $sftp->put($src, $dest);
        
        return OK if $ret;
    }
    
    return !OK;
}

sub sshUnlink {
	my ($sftp, $index, $file) = @_;
    
    die " ----- !!! don't unlink root dir / " if $file eq '/';
    
    if (defined($sftp) && sshExist($sftp, $index, $file)) {
    	my $ret = $sftp->do_remove($file);
        
        if ($ret) {
        	say "<$index !!: Can not delete $file";
        	return !OK;
        }
        
        say "<$index unlink $file";
    }
    
    return OK;
}

sub sshExist {
	my ($sftp, $index, $file) = @_;
    
    if (defined($sftp)) {
        my @x = $sftp->ls(dirname($file));
        my $base = basename($file);
        
        for my $f (@x) {
        	if ($f->{filename} eq $base) {
        		return OK;	
        	}
        }
    }
    
    say "<$index remote file $file not exist.";
    
    return !OK;
}

sub localExist {
	my ($i, $f) = @_;
	
	if (! -e $f) {
		say "<$i local file $f not exist.";
		return !OK;
	} else {
		return OK;
	}
}

sub localUnlink {
	my $i = shift @_;
	
	say "<$i delete @_" if (unlink @_);
}

sub localCopy {
	my ($i, $k, $v) = @_;
	
	say "<$i copy $k -> $v" if (copy $k, $v);
}

sub readList {
	my $file = shift @_;
	
	open my $fh, '<', $file or die "Can not open file $file";
	
	my %ret;
	
	foreach (<$fh>) {
		chomp;
		
		next if (/\A#/);
		
		next if (/\A\Z/);
		
		next if (/\A\s*\Z/);

		my ($k, $v) = split(/\s+/);
		
		$ret{$k} = $v;
	}
	
	close($fh);
	
	%ret;
}

sub checkMode {
	my $mode = shift @_;
	
	if ($mode eq "k" || $mode eq "up" || $mode eq "left") {
		return OK;
	}
	if ($mode eq "v" || $mode eq "down" || $mode eq "right") {
		return !OK;
	}
	
	return undef;
}

sub printOptions {
	say 'remote = \'' . $remote . '\'';
	say 'cplist = \'' . $cplist . '\'';
	say 'mode = \'' . $mode . '\'';
	say 'ssh<ip> = \'' . $ssh{'ip'} . '\'';
	say 'ssh<user> = \'' . $ssh{'user'} . '\'';
	say 'ssh<pass> = \'' . $ssh{'pass'} . '\'';
}

sub isIp {
	$_ = shift @_;
	
	if (/\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}/) {
		say $_;
		return OK;
	} else {
		return !OK;
	}
}

sub errExit {
	say 'Error in file ' . __FILE__ . ' line ' .__LINE__ . ', Errmsg => [' . (shift @_) . ']';
	exit;
}