Perl Net::OpenSSH and rsync_get()

Viewed 50

I'm trying to rsync files in a perl script from a remote directory based on the ctime of a file on the remote server using rsync and having some difficulty.

use strict;
use Net::OpenSSH;
my $user = "phil";
my $password = 'pass';
my $host = "xavier";
my $local_rules = "/etc/mail/rules.cf";
my $remote_rules = "/etc/mail/rules.cf";
my $keypath = "$userhome/.ssh/scp-key.key";
my $ssh = Net::OpenSSH->new($host, user => $user, passphrase => $password, key_path => $keypath);

$ssh->rsync_get({exclude => '*~', archive => 1, safe_links => 1, verbose => 1,
        files_from => "<(find /var/spool/dir/quarantine -cnewer /home/phil/last-run -type f -exec basename {} \\;)>"}, '/var/spool/dir/quarantine/','/home/phil/quarantine/');

When executing, it fails with the following:

rsync: failed to open files-from file <(find /var/spool/dir/quarantine -cnewer /home/phil/last-run -type f -exec basename {} \;)>: No such file or directory
rsync error: syntax or usage error (code 1) at main.c(1765) [client=3.2.4]

When I execute the find command manually on the remote server, it produces a list of files.

I understood the find was executed on the remote host, but perhaps that's not the case?

What am I missing? Is there a better way to do this?

1 Answers

The argument files_from to rsync_get() is quoted before being passed to the ssh command line. The quoting prevents the Shell from recognizing the meta characters in "<(find /var/spool/dir/quarantine -cnewer /home/phil/last-run -type f -exec basename {} \\;)". Please report this at the issue tracker and ask for advice.

As a workaround, you can create the files_from file in advance:

use File::Temp qw(tempfile);
my ($fh, $tempfile) = tempfile();
my $res = system "find /var/spool/dir/quarantine -cnewer /home/phil/last-run -type f -exec basename {} \\; > $tempfile";
die "find command failed" if $res != 0;

Then, run rsync_get() like this:

$ssh->rsync_get(
  {
    exclude => '*~', 
    archive => 1, 
    safe_links => 1, 
    verbose => 1,
    files_from => $tempfile
  }, 
  '/var/spool/dir/quarantine/',
  '/home/phil/quarantine/'
);

Edit:

To get the file list from the remote instead, you can try

use feature qw(say);
use File::Temp qw(tempfile);
my @files = $ssh->capture("find /var/spool/dir/quarantine -cnewer /home/phil/last-run -type f -exec basename {} \\;") or
  die "remote command failed: " . $ssh->error;
my ($fh, $tempfile) = tempfile();
say $fh $_ for @files;
close $fh;
Related