Command-Line Smackdown: cp vs. ditto

There are a couple methods for copying files via the command-line in OSX. The standard UNIX cp command exists, as it does on all *NIX systems. Historically -- that is, through Mac OS X 10.3 -- it's had certain limitations with regards to the HFS+ filesystem, however. Specifically, the cp command was never able to handle resource forks common to that filesystem. Any files copied via cp would have their resource forks stripped, which in some cases would render the files useless. The solution was to use a Mac-specific command called ditto. When supplied with the proper arguments, ditto can copy files and retain their resource forks. It's a great tool, with a lot of other features, and I use it all the time.

In Mac OSX 10.4 (Tiger), cp -- and most other UNIX commands -- have been enhanced to remedy the HFS+ resource restrictions. Using cp to copy files in Tiger (or between two systems running Tiger) will handle resource forks quite seamlessly, and the command works just as it would on any *NIX system. So I've been trying to revert to using cp like a regular UNIX fellow, but I still find myself preferring ditto, for a few reasons.

The ditto command has a few idiosyncrasies that anyone who's coming from traditional UNIX and is used to cp might find distressing. Indeed, I initially found them to be confusing. The main difference lies in how each command specifies the copy behavior for files in directories. The cp command uses a trailing slash to indicate that the contents of the directory -- but not the directory itself -- are to be copied to the specified location. So a command like this:

cp -R /Users/systemsboy/ /Users/test

will copy the files inside the systemsboy directory to the test directory. Whereas:

cp -R /Users/systemsboy /Users/test

will copy the directory systemsboy and its contents to the test directory.

This is a nice way to do things. It's how most *NIX commands work, and to my mind makes a lot of sense. But it is not how ditto works. The ditto command doesn't care about trailing slashes at all. The ditto command always copies the contents of a directory. So, following the example above:

ditto -rsrc /Users/systemsboy/ /Users/test

will copy the contents of systemsboy to test. And so will:

ditto -rsrc /Users/systemsboy /Users/test

I repeat, ditto does not give a shit about the trailing slash, and always copies the contents only. The two above commands, therefore, function the same, trailing slash or no. So, if you want to copy the entire systemsboy directory to the test directory, you must say so thusly:

ditto -rsrc /Users/systemsboy /Users/test/systemboy

Here you are specifying a directory that does not exist. If you tried to do that with cp you'd get an error message stating that the directory didn't exist. One nice thing about ditto is that it will create the directory for you. There are other niceties as well.

The ditto command, by default, preserves mode, access time, permissions and all other file attributes. If you want these functionalities with cp, you'll need to specify them with the -p (preserve) flag. The ditto command also has other uses. For instance, ditto can be used to create a .zip file of a directory that is comparable to those created in the Finder.

So, despite the fact that the latest versions of standard UNIX commands included with 10.4 are resource-fork aware and can finally be used as they would on any *NIX system, I've become accustomed to using commands included by Apple to mitigate the previous lack of support of the standard UNIX ones. The ditto command still has a very useful and important place in my admin toolbox, and I continue to use it in favor of cp in many situations. It's tried, it's true, and I trust it. And it will work with previous versions of the Mac OS.