Mac OS X Commandline: ditto
One of the things I love about Mac OS X is that, beneath the pretty and functional surface most people see, there’s a complete UNIX environment with all the tools a commandline jockey needs. And if something is missing, just install Xcode and homebrew and you’re good.
With this post I will kick off a series of short articles, published at highly irregular intervals, about the commandline utilities that come with Mac OS X and isn’t part of other UNIX-like operating systems.
First up: ditto
.
Ditto can “… copy directory hierarchies, create and extract archives”, and it does so with a complete understanding of the peculiarities of Mac OS X filesystem resource forks, extended attributes, Access Control Lists and quarantine information.
All of these features are on by default since Mac OS X 10.5, as this is almost always what you want for backup purposes. There are quite self-explanatory --norsrc
, --noextattr
, --noacl
and --noqtn
options to shut those features off.
Copying a directory is straightforward:
% ls src
a b c
% ditto src dest
% ls -F
dest/ src/
% ls dest
a b c
Use the -v
or -V
options to make ditto
more verbose about what it’s doing.
When creating an archive using the -c
option, files are per default stored as CPIO archives, or as ZIP archives with the -k
option. CPIO archives can optionally be compressed with either gzip
or bzip2
, the -z
and -j
options respectively.
A feature of ditto
is that it does not embed the parent directory in the archive by default, use --keepParent
for this. You also need to explicitly specify the output directory when extracting an archive. There’s a certain logic to this, given the directory copying capabilities of ditto
, but it’s counterintuitive compared to other common commandline archiving utilities. Let’s see an example, first without --keepParent
:
% ls dir/
a b c
% ditto -ck dir dir.zip # Create archive.
% ls -F
dir/ dir.zip
% ditto -xk dir.zip output # Extract archive to ‘output’.
% ls output
a b c
This is not how tar
works for example. To get a more tar
-like behaviour, use --keepParent
when creating the archive:
% ditto --keepParent -ck dir dir.zip
% ditto -xk dir.zip output
% ls -F output
dir/
% ls -F output/dir
a b c
See? Nevermind that tar
defaults to the current directory as output directory and needs a -C
option to output to another directory.
If you are creating an archive to share with someone not on a Mac be sure to use the --norsrc
option to avoid creating ._*
files on the target system. There’s no file exclusion option for ditto, so it is not directly possible to avoid archiving the .DS_Store
files. A workaround is the --bom
option, but then you need to create a BOM file, and that’s overkill in most situations, and—I think—another post entirely.