35

I am using scp to copy a directory from one remote server to a new directory (IE just changing the name) on another remote server like:

scp -prq server1:dir1 server2:dir2

This works fine if dir2 does not exist on server2, it creates a new directory called dir2 which contains everything from dir1 on server1.

The problem comes when dir2 already exists on server2 (NOTE: I have no way of knowing this in advance or of doing a remove on dir2 on server2 beforehand) - what happens is I get a copy of dir1, called dir1, in dir2.

I am sure there is something basic I am missing, but I just cannot seem to work it out.

Any help much appreciated!

Regards,

Giles

Okay, I have less than 10 rep and cannot be ar$ed to wait 8 hrs so here is what I got:

Here is a script that works for me:

#!/bin/sh
echo "method 1"
scp -prq server1:dir1/* server2:dir2/ >/dev/null  2>&1

if [ "$?" -ne "0" ]; then
        echo "failed ... trying method 2"
        scp -prq server1:dir1 server2:dir2
fi

exit

Still not sure how to do this in a single command or even if possible.

Cheers @mindthemonkey, sometimes just getting a fresh viewpoint can help point the way.

Giles
  • 351
  • 1
  • 3
  • 4
  • you have scp access but not ssh? – Matt Sep 12 '13 at 12:54
  • That is correct – Giles Sep 12 '13 at 13:13
  • The only problem there is you will try the second copy on any failure, which is not necessarily dir2 not existing. Maybe if you can come up with a test that does virtually nothing (say copy a blank dir). Then based on the output either run scp1 or scp2 – Matt Sep 12 '13 at 13:50
  • Good point, I`ll keep that in mind going forward and repost if I come up with something. – Giles Sep 12 '13 at 14:02
  • [Can you sftp?](http://unix.stackexchange.com/a/55194/22470) then check the output of a `cd dir2`. – Matt Sep 12 '13 at 14:13

4 Answers4

41

Use this "dot" syntax:

scp -prq server1:dir1/. server2:dir2/

This copies the contents of that directory, rather than the directory itself. And I believe it's more portable than * globbing.

chronospoon
  • 581
  • 4
  • 4
  • 5
    -p ⇒"Preserves modification times, access times, and modes from the original file." -r ⇒ "Recursively copy entire directories." -q ⇒ "Disables the progress meter." Source: https://www.computerhope.com/unix/scp.htm – kr85 Mar 16 '18 at 03:41
  • 16
    This gives me an error: `scp: error: unexpected filename: .` – Andrew Koster Apr 27 '19 at 22:53
  • This may have been patched as of Nov 2018; I can't tell if this just applies to `.` or `dir1/.` as well: https://superuser.com/a/1403506/255506 – chronospoon May 03 '22 at 16:26
2

Normally to control directory creation you need to use a trailing / to imply a complete path but I think this will then fail to create the directory if it doesn't exist:

scp -prq server1:dir1/* server2:dir2/

This could also miss hidden . files due to the * glob expansion (without some tricky shell specific work)

You can approach it differently with ssh and tar.

ssh server1 "cd dir1 && tar -cf - ." | ssh server2 "( mkdir -p dir2; cd dir2 && tar -xf - )"

But this means traffic goes via your local machine.

Matt
  • 1,537
  • 8
  • 11
  • scp -prq server1:dir1/* server2:dir2/ – Giles Sep 12 '13 at 12:54
  • @Giles are you saying that does work? – Matt Sep 12 '13 at 13:00
  • 1
    Odd, I edited that but it has got lost - no,that does not work, if the dir does not exist then scp gives an error. Also I do not have ssh available in this particular case (issue with user rights). This does give me an idea though, as I am doing this in a script I can try the above, capture any error and, on error, try the basic version from my first post. Thanks for the help @mindthemonkey – Giles Sep 12 '13 at 13:12
  • 1
    It errors 'Is a directory' when the destination directory doesn't exist for me. – Matt Sep 12 '13 at 13:16
  • 1
    Yes, me too, kind of an odd error given the directory does not exist. – Giles Sep 12 '13 at 13:31
  • This answer works, the dot-syntax one doesn't. – Andrew Koster Apr 27 '19 at 23:01
0

purge it using ssh first and then recreate it with scp. i.e. in a script file...

ssh -i ~/.ssh/[private_key] user@server2 "rm -rf dir2; exit;"

scp -prq server1:dir1 server2:dir2

Fabze
  • 1
0

I've banged my head against exactly this same issue, and what I ended up doing was semi-punting: if dir2 is [STUFF]/parent/child2, I rename or copy or link dir1 (as appropriate for the situation) to dir1_child2 on server1 so that its last path component is also child2, and then just execute

scp -prq server1:dir1_child2 server2:[STUFF]/parent

This runs whether or not child2 is present in dir2's parent directory, and happily replaces dir2 if it is.

Glen Whitney
  • 101
  • 1