Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

scp with special characters programmatically

Tags:

bash

unix

scp

ssh

perl

I have been searching for this for a while, and can't find a satisfactory answer.

I have a perl script that needs to copy a file from one host to another, essentially

sub copy_file{
    my($from_server, $from_path, $to_server, $to_path, $filename) = @_;

    my $from_location = "$from_server:\"\\\"${from_path}${filename}\\\"\"";
    my $to_location = $to_path . $filename;
    $to_location =~ s/\s/\\\\ /g;
    $to_location = "${to_server}:\"\\\"${to_location}\\\"\"";

    return system("scp -p $from_location $to_location >/dev/null 2>&1"");
}

The problem is, some of my filenames look like this:

BLAH;BLAH;BLAH.TXT
Some really nicely named file( With spaces, prentices, &, etc...).xlx

I am already handling whitespaces, and the code for that is quite ugly since on each side, the files could be local or remote, and the escaping is different for the from and to part of the scp call.

what I am really looking for is either to somehow to escape all possible special characters or somehow bypass the shell expansion entirely by using POSIX system calls. I am ok with writing a XS Module if need be.

I have the correct keys set up in the .ssh directory Also I am not honestly sure which special characters do and don't cause problems. I would like to support all legal filename characters.

like image 212
Smartelf Avatar asked Feb 16 '26 23:02

Smartelf


1 Answers

Say you want to copy file foo(s) using scp.

As shown below, scp treats the source and target as shell literals, so you pass the following arguments to scp:

  • scp
  • -p
  • --
  • host1.com:foo\(s\) or host1.com:'foo(s)'
  • host2.com:foo\(s\) or host2.com:'foo(s)'

You can do that using the multi-argument syntax of system plus an escaping function.

use String::ShellQuote qw( shell_quote );

my $source = $from_server . ":" . shell_quote("$from_path/$filename");
my $target = $to_server   . ":" . shell_quote("$to_path/$filename");

system('scp', '-p', '--', $source, $target);

If you really wanted to build a shell command, use shell_quote as usual.

my $cmd = shell_quote('scp', '-p', '--', $source, $target);

$ ssh [email protected] 'mkdir foo ; touch foo/a foo/b foo/"*" ; ls -1 foo'
*
a
b

$ mkdir foo ; ls -1 foo

$ scp '[email protected]:foo/*' foo
*              100%    0     0.0KB/s   00:00
a              100%    0     0.0KB/s   00:00
b              100%    0     0.0KB/s   00:00

$ ls -1 foo
*
a
b

$ rm foo/* ; ls -1 foo

$ scp '[email protected]:foo/\*' foo
*              100%    0     0.0KB/s   00:00

$ ls -1 foo
*
like image 127
ikegami Avatar answered Feb 19 '26 18:02

ikegami



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!