Inconsistent Behaviors among cp, rsync, and Others
Inconsistent behaviors for coping directory among cp
, rsync
, aws s3 cp
, aws s3 sync
, az storage copy
and gsutil cp
are sometimes confusing. Here is a list of their behaviors and examples for you to better understand them.
Assume we have the following directory structure in current directory and cloud storage before running following commands:
.
├── dir1
│ └── file1
├── dir2
│ └── file2
└── dir3
└── file3
cp
- When destination directory does NOT exist,
- the destination directory is created, and the content of source directory is copied.
- When destination directory exists,
- by default, both the directory itself and its content are copied to the destination directory;
- unless the source directory is
.
, or is suffixed with/.
, by then, only the content of source directory is copied.
Note: Suffix a directory with /
is the same as not suffixing it.
Note: The behavior of cp
is consistent with mv
.
cp Examples
$ # Destination not exists
$ cp -r -v dir1 dir4
'dir1' -> 'dir4'
'dir1/file1' -> 'dir4/file1'
$ # Source dir suffixed with /.
$ # Destination dir not exists
$ cp -r -v dir1/. dir5
'dir1/.' -> 'dir5'
'dir1/./file1' -> 'dir5/file1'
$ # Destination dir exists
$ cp -r -v dir1 dir2
'dir1' -> 'dir2/dir1'
'dir1/file1' -> 'dir2/dir1/file1'
$ # Source dir suffixed with /.
$ # Destination dir exists
$ cp -r -v dir1/. dir3
'dir1/./file1' -> 'dir3/./file1'
rsync
- If destination directory does NOT exist, it's created;
-
- by default, both the directory itself and its content are copied to the destination directory;
- unless the source directory is
.
, or is suffixed with/
or/.
, by then, only the content of source directory is copied.
Note: Suffix a directory with /
is the same as suffixing it with /.
.
rsync Examples
$ # Destination not exists
$ rsync -r dir1 dir4
$ tree dir4
dir4
└── dir1
└── file1
1 directory, 1 file
$ # Source dir suffixed with /.
$ # Destination not exists
$ rsync -r dir1/. dir5
$ tree dir5
dir5
└── file1
0 directories, 1 file
$ # Destination dir exists
$ rsync -r dir1 dir2
$ tree dir2
dir2
├── dir1
│ └── file1
└── file2
$ # Source dir suffixed with /.
$ # Destination dir exists
$ rsync -r dir1/. dir3
$ tree dir3
dir3
└── file1
0 directories, 1 file
aws s3 cp / aws s3 sync
It's always the content of source directory are copied to the destination directory.
Note: Suffix a directory with /
is the same as not suffixing it or suffixing it with /.
.
aws Examples
$ aws s3 cp --recursive dir1 s3://zzz.buzz/dir2
upload: dir1/file1 to s3://zzz.buzz/dir2/file1
$ aws s3 cp --recursive dir1/. s3://zzz.buzz/dir3
upload: dir1/file1 to s3://zzz.buzz/dir3/file1
$ aws s3 cp --recursive dir1 s3://zzz.buzz/dir4
upload: dir1/file1 to s3://zzz.buzz/dir4/file1
$ aws s3 cp --recursive dir1/. s3://zzz.buzz/dir5
upload: dir1/file1 to s3://zzz.buzz/dir5/file1
$ aws s3 cp --recursive s3://zzz.buzz/dir2 dir1
download: s3://zzz.buzz/dir2/file1 to dir1/file1
$ aws s3 sync dir1 s3://zzz.buzz/dir2
upload: dir1/file1 to s3://zzz.buzz/dir2/file1
$ aws s3 sync dir1/. s3://zzz.buzz/dir3
upload: dir1/file1 to s3://zzz.buzz/dir3/file1
$ aws s3 sync dir1 s3://zzz.buzz/dir4
upload: dir1/file1 to s3://zzz.buzz/dir4/file1
$ aws s3 sync dir1/. s3://zzz.buzz/dir5
upload: dir1/file1 to s3://zzz.buzz/dir5/file1
$ aws s3 sync s3://zzz.buzz/dir2 dir1
download: s3://zzz.buzz/dir2/file1 to dir1/file1
az storage copy
It's always the directory iteself and its content get copied to the destination directory.
Note: Suffix a directory with /
is the same as not suffixing it or suffixing it with /.
.
az Examples
$ az storage copy -r -s dir1 -d https://zzzbuzz.blob.core.windows.net/container/dir2
$ az storage blob list --account-name zzzbuzz -c container --prefix dir2 --query "[].{name:name}" --output tsv
dir2/dir1/file1
dir2/file2
$ az storage copy -r -s dir1/. -d https://zzzbuzz.blob.core.windows.net/container/dir3
$ az storage blob list --account-name zzzbuzz -c container --prefix dir3 --query "[].{name:name}" --output tsv
dir3/dir1/file1
dir3/file3
$ az storage copy -r -s dir1 -d https://zzzbuzz.blob.core.windows.net/container/dir4
$ az storage blob list --account-name zzzbuzz -c container --prefix dir4 --query "[].{name:name}" --output tsv
dir4/dir1/file1
$ az storage copy -r -s dir1/. -d https://zzzbuzz.blob.core.windows.net/container/dir5
$ az storage blob list --account-name zzzbuzz -c container --prefix dir5 --query "[].{name:name}" --output tsv
dir5/dir1/file1
$ az storage copy -r -s https://zzzbuzz.blob.core.windows.net/container/dir1 -d download
$ tree download
download
└── dir1
└── file1
1 directory, 1 file
gsutil cp
- When destination directory does NOT exist,
- the destination directory is created, and the content of source directory is copied.
- When destination directory exists,
- by default, both the directory itself and its content are copied to the destination directory;
- unless the source directory is
.
, or is suffixed with/.
, by then, only the content of source directory is copied.
Note: Suffix a directory with /
is the same as not suffixing it.
Note: The behavior of gsutil cp
is consistent with cp
.
gsutil Examples
$ # Destination not exists
$ gsutil cp -r dir1 gs://zzz.buzz/dir4
$ gsutil ls -r gs://zzz.buzz
gs://zzz.buzz/dir4/:
gs://zzz.buzz/dir4/file1
$ # Source dir suffixed with /.
$ # Destination not exists
$ gsutil cp -r dir1/. gs://zzz.buzz/dir5
$ gsutil ls -r gs://zzz.buzz
gs://zzz.buzz/dir5/:
gs://zzz.buzz/dir5/file1
$ # Destination dir exists
$ gsutil cp -r dir1 gs://zzz.buzz/dir2
$ gsutil ls -r gs://zzz.buzz
gs://zzz.buzz/dir2/:
gs://zzz.buzz/dir2/file2
gs://zzz.buzz/dir2/dir1/:
gs://zzz.buzz/dir2/dir1/file1
$ # Source dir suffixed with /.
$ # Destination dir exists
$ gsutil cp -r dir1/. gs://zzz.buzz/dir3
$ gsutil ls -r gs://zzz.buzz
gs://zzz.buzz/dir3/:
gs://zzz.buzz/dir3/file1
gs://zzz.buzz/dir3/file3