Search code examples
perlrsyncquoting

Perl: rsync with 'ssh -q' fails with exit code 14


I need to run an rsync task from a perl script. (The code below is part of a larger script and using perl is unavoidable.) Since rsync is being run noninteractively, I'd like to avoid printing the ssh login banner from the server I'm uploading files to. I have seen that using the command rsync -e 'ssh -q' is the way to do this, and this works from the command line. (Well, I'm using the long option format --rsh='ssh -q' for readability in the script.)

However, I cannot seem to get this to work from my perl script. Here is the relevant part of the code:

#!/usr/bin/env perl

use strict;
use warnings;

my $src = '/path/to/myfile';
my $dest = 'remote:/path/to/target';

my @rsync_cmd;

# this one works, returns 0
@rsync_cmd = ('rsync', '--archive', '--update', '--rsh=ssh', $src, $dest);
system(@rsync_cmd);
print "Exit code: ", $? >> 8, "\n\n";

# this one doesn't, returns 14
@rsync_cmd = ('rsync', '--archive', '--update', '--rsh=\'ssh -q\'', $src, $dest);
system(@rsync_cmd);
print "Exit code: ", $? >> 8;

The first command works fine and returns 0. The second command returns 14 (Error in IPC code) and gives the following output:

rsync: Failed to exec ssh -q: No such file or directory (2)
rsync error: error in IPC code (code 14) at pipe.c(85) [sender=3.1.1]
rsync: connection unexpectedly closed (0 bytes received so far) [sender]
rsync error: error in IPC code (code 14) at io.c(226) [sender=3.1.1]

As I said, however, running rsync with --rsh='ssh -q' from the command line does work fine, so I'm not sure what's going on here. I've tried various other ways of quoting the ssh command:

  • '--rsh="ssh -q"'
  • q{--rsh='ssh -q'}
  • q{--rsh="ssh -q"}

(plus a few more) and all of these give the same exit code (14).

Other things I've tried with no success:

  • Replacing ssh with /usr/bin/ssh in case rsync was having trouble finding the ssh binary.
  • Using short option format -e 'ssh -q'.
  • Using File::Rsync module (perl wrapper for rsync) to try to avoid quoting problems.
  • Setting the RSYNC_RSH environment variable via $ENV{'RSYNC_RSH'}=q{ssh -q}.
  • Removing the --archive and --update options for testing purposes.

All of these result in the same exit code, 14. I am at my wits' end, please help.


Solution

  • system(..., "--rsh=ssh -q", ...)

    You are using the system LIST syntax, which already passes each argument uninterpolated to the called program. "--rsh=ssh -q" from Perl is equivalent to --rsh='ssh -q' in the shell. The quotes will treat the ssh and the -q as part of the same argument to the command, but the quotes themselves will be interpolated away in the shell, so rsync will receive the argument as --rsh=ssh -q.