ZeroLimits

Today I Learned

Stuff I learned today

2026-10-15

The cp -R command works slightly differently on macOS and Linux. For instance, let’s say I want to recursively copy a directory called directory/ into dist/. On macOS, if I do:

cp -R directory dist

That’ll create a directory structure like this:

dist/
  directory/
    files...

But if I add a trailing slash to directory:

cp -R directory/ dist

then it’ll copy the files inside directly into dist/:

dist/
  files...

However, both of these commands have the same output on Linux:

# both of these do the same thing
cp -R directory dist
cp -R directory/ dist
dist/
  directory/
    files...

In order to get files... to be directly under dist/, you need to add a dot to the end of directory/:

cp -R directory/. dist
dist/
  files...

To be fair, this is pretty clearly written in the cp manpage:

-R    If source_file designates a directory, cp copies the directory and the entire subtree connected at that point.
      If the source_file ends in a /, the contents of the directory are copied rather than the directory itself.
      This option also causes symbolic links to be copied, rather than indirected through, and for cp to create
      special files rather than copying them as normal files.  Created directories have the same mode as the
      corresponding source directory, unmodified by the process' umask.