Note that there's a problem in your code. Leaving $*
unquoted never makes sense. $*
is the concatenation of the positional parameters with the first character of $IFS
. And then, though there are some variations in behaviour when IFS is empty, that is then subject to word splitting and filename generation. Here, you want:
#!/bin/sh -
exec /bin/cp --reflink=auto "$@"
"$@"
expands to all the positional parameters as separate arguments.
If you want to update /bin/cp
and the change to be preserved upon updates, then most systems will have a canonical way to do that. On Debian and derivatives, you'd do:
$ sudo dpkg-divert --local --rename /bin/cp
Adding 'local diversion of /bin/cp to /bin/cp.distrib'
Then write /bin/cp
as:
#! /bin/sh -
exec "$0.distrib" --reflink=auto "$@"
Every update of coreutils will update cp.distrib
instead of cp
.
Note that there's a performance implication in that it needs to load and run sh
before running cp
. That's not as bad on Debian where /bin/sh
is based on dash
.
That also means error messages and help messages will mention cp.distrib
instead of cp
:
$ cp
/bin/cp.distrib: missing file operand
Try '/bin/cp.distrib --help' for more information.
That last part, you can work around by writing the script as:
#! /bin/bash -
exec -a "$0" "$0.distrib" --reflink=auto "$@"
(same with ksh93
or zsh
all like bash
bloated shells compared to dash
though).
It will not be strictly equivalent as $0
will contain the path to that script as opposed to the argv[0]
cp
initially received but at least it will be something like /bin/cp
instead of /bin/cp.distrib
.
cp --reflink=always
is almost certainly working correctly. If it weren't, you would be getting an error. By design, that's the difference between --reflink=always
and --reflink=auto
. The error would look like this:
# Filesystem that does not support the feature at all
cp: failed to clone `xx' from `yy': Inappropriate ioctl for device
# Filesystem that does support it, but copy across filesystems
cp: failed to clone `xx' from `yy': Invalid cross-device link
Are you copying a directory structure with lots of small files? In that case cp
still has to create every directory and open and close every file, so it will still take time, unlike btrfs subvolume snapshot
. That most likely explains the time it takes to perform the operation.
Best Answer
It's not the default since for robustness reasons one may want a copy to take place to protect against data corruption. Also for performance reasons you may want the writes to happen at copy time rather than some latency sensitive process working on a CoW file and being delayed by the writes possibly to a different part of a mechanical disk. Note that from coreutils v8.24 mv will reflink by default, since it doesn't have the above constraints. Note also that the major release after v8.32 will try to reflink in cp by default, as such a change is not appropriate for a minor release.