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.
By default, ditto does not overwrite existing files in the target directory. Also, ditto, 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 -n (no overwrite) and -p (preserve) flags, respectively. 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.
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.
By default, ditto does not overwrite existing files in the target directory. Also, ditto, 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 -n (no overwrite) and -p (preserve) flags, respectively. 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.
in the man page of Ditto I read:
--rsrc
preserve resource forks and HFS meta-data. ditto will store this data in Carbon-compatible ._ AppleDouble files on filesystems that do not natively support resource forks. As of Mac OS X 10.4, --rsrc is default behavior.
So I guess you dont't have to use --rsrc
?
2:48 PM
Yes, that is correct. I think I even read that once, long ago, but decided to keep using the -rsrc flag for safety's sake. Keeping -rsrc in place is good because it allows for backwards compatibility. So any script written with the -rsrc option will work on any version of the OS. If you still support Panther clients, you will need -rsrc.
But thanks for the info! Good to know.
-systemsboy
7:05 PM
The only thing I don't like about ditto is that it will copy files over even if they already exist in the destination folder. Or am I doing something wrong?
1:33 PM
Macvoodoo,
Yes, that's correct. The ditto command will copy over files that exist in the destination. Actually, I didn't think this was the case, but I just tested it, and that is indeed the behavior.
For the record, this is also how the cp command behaves.
If you're looking for something that does not overwrite destination files, you should look into the rsync command. Good stuff, that rsync.
-systemsboy
» Post a Comment