1

I have local file structure:

/tmp/24
    /dir1
        /file1
        /file2
    /dir2
        /file3
        /file4

and I want to upload it to remote compute. When I use

rsync /tmp/24 host:/target

it creates it inside target directory on the remote host (/target/24/dir1/file1, ...). But when I use it like this

rsync /tmp/24/ host:/target

it does what I want and that is to create them like this: /target/dir1/file1. However, scp does the first thing if the target folder already exists and second when it doesn't regardless of the path ends with / or not. How can I force scp to behave like rsync in the second example?

5

The trailing '/' on the source directory name is a subtlety of rsync. Pay attention to it.

rsync

A trailing slash on the source effectively means "copy the contents of this directory, not the directory itself". Without the trailing slash, it means "copy the directory".

So rsync -a tmp/24/ host:/target will copy the contents of "/tmp/24/" into "host:/target/…".

But rsync -a tmp/24 host:/target will copy the directory "/tmp/24/" (and its contents) into "host:/target/24/…".

It doesn't matter if "host:/target/" doesn't already exist; it will be created if necessary and the results are the same either way.

(Trailing slashes on the destination don't matter.)

┌─────────────────────────┬───────────────┬───────────────────────┐
│ rsync                   │ target exists │ target does not exist │
├─────────────────────────┼───────────────┼───────────────────────┤
│ rsync -a tmp/24 target  │ target/24/…   │ target/24/…           │
├─────────────────────────┼───────────────┼───────────────────────┤
│ rsync -a tmp/24/ target │ target/…      │ target/…              │
└─────────────────────────┴───────────────┴───────────────────────┘

scp

Slashes do not matter at all, only whether the target directory exists or not. If it exists, then the source directory is copied into the target directory, otherwise the target directory is created as a clone of the source.

┌───────────────────────┬───────────────┬───────────────────────┐
│ scp                   │ target exists │ target does not exist │
├───────────────────────┼───────────────┼───────────────────────┤
│ scp -r tmp/24 target  │ target/24/…   │ target/…              │
├───────────────────────┼───────────────┼───────────────────────┤
│ scp -r tmp/24/ target │ target/24/…   │ target/…              │
└───────────────────────┴───────────────┴───────────────────────┘

So you're right, you should just do ssh host mkdir -p /target first, and then the behavior will be the same as for rsync.

But why not just use rsync? It does so much more, such as partial transfers, interrupted transfers, and compressed data.

rsync -azu tmp/24 host:/target

cp

And for completeness: On Mac, the trailing '/' gives you rsync semantics as long as target already exists.

┌──────────────────────┬───────────────┬───────────────────────┐
│ cp (Mac)             │ target exists │ target does not exist │
├──────────────────────┼───────────────┼───────────────────────┤
│ cp -a tmp/24 target  │ target/24/…   │ target/…              │
├──────────────────────┼───────────────┼───────────────────────┤
│ cp -a tmp/24/ target │ target/…      │ target/…              │
└──────────────────────┴───────────────┴───────────────────────┘

Under Linux, slashes do not matter at all, same as scp:

┌──────────────────────┬───────────────┬───────────────────────┐
│ cp (Linux)           │ target exists │ target does not exist │
├──────────────────────┼───────────────┼───────────────────────┤
│ cp -a tmp/24 target  │ target/24/…   │ target/…              │
├──────────────────────┼───────────────┼───────────────────────┤
│ cp -a tmp/24/ target │ target/24/…   │ target/…              │
└──────────────────────┴───────────────┴───────────────────────┘

ditto

Adding on… ditto(1) is a Mac OS tool to clone a directory. It makes as an exact a copy as possible.

Slashes do not matter at all. Whether or not the target directory already exists does not matter.

┌──────────────────────┬──────────┐
│ ditto tmp/24 target  │ target/… │
└──────────────────────┴──────────┘

If target already exists, previously-existing files are overwritten unconditionally. Files in target which are not in the source are left alone.

  • really nice sum up, thank you. Reason why I'm not using rsync is that when showing progress (I think rsync --progress), it freezes up for 5-10 seconds after last file and produces no output. I'm not sure what is the cause (there could be plenty issues in my case), but since I don't really need any of those fancy rsync's features (I'm just uploading data into virtualbox machine), I'd prefer to go with scp. – graywolf Jun 29 '16 at 18:51
1

huh, so my problem can be solved like this:

ssh host "mkdir -p /target"
scp tmp/24/* host:/target

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.