cp, trailing slash, and copying to the same vs. to another directory

To copy a directory to another directory, the first directory should be written without the trailing slash:

# example 1
# this command will copy dir1 to dir2
# (dir2 is preexisting)
cp -Rip dir1 dir2/

Otherwise, the command will copy directory contents and not the directory itself:

# example 2
# this command will copy dir1 contents to dir2
# (dir2 is preexisting)
cp -Rip dir1/ dir2/

I do understand the difference between dir1 and dir1/ here, and the difference between how these two commands behave doesn’t confuse me.

But to copy the directory not to another directory but to the same directory where it is currently located, the trailing slash won’t make any difference. Why?

# example 3
# any of these commands will make a dir1 copy
# (dir1-copy isn't preexisting)
cp -Rip dir1 dir1-copy/
cp -Rip dir1/ dir1-copy/

And another, closely related question. Why there is no difference between how mv dir1/ dir2/ and mv dir1 dir2/ work? In other words, why, in respect of trailing slash in the end of the source directory, mv follows the logic of the third cp example, and not the logic of examples one and two?

macOS 14.3.1, zsh 5.9 (x86_64-apple-darwin23.0)

Asked By: jsx97

||

The difference in behavior between cp -R dir1 dir2 and cp -R dir1/ dir2 is a feature that was added to FreeBSD in version 5.4. At least, that’s when the following sentence was added to the manual for the description of the -R option:

If the source_file ends in a /, the contents of the directory are copied rather than the directory itself.

It’s possible that this behavior was older and 5.4 just filled an omission in the documentation. There’s nothing about this in the 5.0, 5.1, 5.2, 5.3 or 5.4 release notes. I haven’t gone source diving.

Modern versions of FreeBSD, and macOS which has command line utilities from FreeBSD, have kept this behavior. Other systems (GNU, BusyBox, OpenBSD, NetBSD, or anything POSIX-compliant) don’t have this behavior: cp -R dir1/ dir2 and cp -R dir1 dir2 have exactly the same behavior (except when dir1 is a symbolic link: dir1/ causes the link to be followed).

The FreeBSD behavior may have been inspired by rsync, which has the same distinction. I do find it strange that they made a backward-incompatible change that deviated

But to copy the directory not to another directory but to the same directory where it is currently located, the trailing slash won’t make any difference. Why?

It’s a weird design decision. Or maybe it wasn’t a design decision, but an implementation bug (parsing the source path and deciding that the part after the trailing slash is a path component) that they decided to call a feature. With rsync, the trailing slash keeps its behavior even when the destination directory doesn’t exist.

Why there is no difference between how mv dir1/ dir2/ and mv dir1 dir2/ work?

There isn’t supposed to be a difference (assuming dir1 isn’t a symbolic link), so that’s just the normal state of affairs.

Categories: Answers Tags: , , ,
Answers are sorted by their score. The answer accepted by the question owner as the best is marked with
at the top-right corner.