2018-07-31
The hidden danger of using rsync
to copy files instead of cp
I have a long standing reflexive habit that most of them time when
I want to copy files around, I reach for 'rsync -a
' by default.
I do it on the command line, and I do it in things like our local
postinstall system setup scripts.
It's not really necessary these days ('cp -a
' now works fine on
everything I commonly use), but I started doing this in an era when
rsync
was the clearly safest choice for a 'copy file, preserving
all attributes, no matter what system I'm on' command. Today I made
a mistake and was reminded that this is not necessarily the best
idea, because there is a small difference in behavior between rsync
and cp
here.
What happened today is that in a system setup script, I wrote:
set -e [...] rsync -a /master/loc/etc/cron.d/cron-thing /etc/crond.d/
I ran the script, it went fine, and then afterward the system didn't
actually seem to be doing what the cron.d
entry was supposed to
have it do. I spent some time wondering if I'd gotten some other bit
of the system setup wrong, so that the script I was invoking from cron
couldn't do anything, and then finally I looked in /etc/cron.d
for
some reason and the penny dropped.
You see, the important difference between rsync
and cp
here is
that rsync will create a destination directory if necessary and
cp won't. The drawback of this sometimes-handy behavior is that
rsync's behavior hides typos. Had I written 'cp -a ...
/etc/crond.d/
', the cp
would have errored out (and then the
entire script would have aborted). With rsync
, it quietly created
/etc/crond.d
and put my cron-thing in it, just as I'd typed but
not as I'd wanted.
After this happened, I went back through this script and turned all
of my reflexive 'rsync -a
' usage into 'cp -a
'. I've been burned
once, I don't need to stub my toe a second time.
I don't currently plan to revise our existing (working) scripts
just for this, but certainly I'm now going to try to shift my
reflexes and use 'cp -a
' in the future.
(In this sort of context, even if I want the directory created too
I think it's better to use 'mkdir -p
' in order to be explicit about
it. On the command line I might exploit rsync
's side effect, but in
a script there's no reason to be that compact and obscure.)