Way to express: `–link` or fall back to ordinary copy in cp (from GNU coreutils)

coreutilscphard link

Is there a way to tell cp to --link (i.e. create hard links), but fall back in the case where I am attempting inter-device hardlinks? Inter-device links aren't possible and would cause cp to fail.

The reason I am asking is because I would like to use this in a GNUmakefile and would prefer a readable command line over some convoluted and lengthy one (or a function, for that matter).

The question is for GNU coreutils (7.4 and 8.13).

Note: right now the workaround would be something like (GNU make recipe syntax):

cp -fl $^ $@ || cp -f $^ $@

This will of course give spurious error messages in case of inter-device links, although succeeding on the second cp call then. Also, then this gets expanded (source form looks readable after all) it won't be too readable anymore.

Best Answer

cp doesn't have this option. You could write a wrapper script, but it's pretty simple.

ln -f $^ $@ 2>/dev/null || cp -f $^ $@

GNU Coreutils 7.5 introduced the --reflink option. If you pass --reflink=auto and the underlying filesystem supports copy-on-write (e.g. Btrfs or ZFS) and the copy happens to be on the same device, then cp will create a new inode but not copy the content; otherwise cp performs a normal copy. This is still not a hard link (the target will always be a different inode), but it's probably even better for your use case. However, if you're on ext4 (like most people nowadays), which doesn't support copy-on-write, this won't help you.

Related Question