If you want to delete all the files that are hard linked to any of the files found via descending foo
, with GNU tools, you could do:
dir=foo
mountpoint=$(df --output=target -- "$dir" | tail -n +2)
awk -v RS='\0' -v ORS='\0' '
ARGIND == 1 {inum[$0]; next}
{i=$0; getline}
i in inum
' <(find -- "$dir" -xdev ! -type d -links +1 -printf '%i\0') \
<(find -- "$mountpoint" -xdev ! -type d -printf '%i\0%p\0') |
xargs -r0 rm -f
rm -rf -- "$dir"
That assumes GNU df
, GNU awk
, GNU find
and a shell like the GNU shell (bash
) that supports process substitution (<(...)
).
That also assumes $dir
doesn't start with -
or doesn't happen to be a find
predicate (like !
, (
...).
Above we look for files on the whole file system $dir
belongs to. You can replace $mountpoint
with just the parent directory of $dir
(.
in this case) or the other subdirs (123 ABC def
here) if you know all the hardlinks are only in there.
In the code above, we record the inode numbers of all the non-directory files with a link count greater than 1 that are found via descending $dir
. And look for those inode numbers in the whole file system (at least sections of it that are not masked by other file systems and that you have permissions to traverse). inode numbers are only unique per-filesystem, so we use -xdev
to make sure we only scan the one file system $dir
is found on.