Tuesday, September 2, 2008

How to find and delete all hard links to a file

Deleting a file is deceptively simple. You can simply use the rm command like this.
$ rm file1


However, if the file has one or more hard links to it, life gets more interesting. You need to seek and destroy all hard links to the file.

A hard link is essentially another name for a file. Hard links to file1 can be created as follows:
$ ln file1 file2
$ ln file1 tmp/file3


file2 and file3 become another name of file1.

How do I know if some file has a hard link to it?

Do a long listing of the file like this.
$ ls -l file1
-rw-r--r-- 3 peter peter 0 2008-09-01 16:15 file1


Note that the hard link count has the value 3 (this is the number to the left of the file owner). It means that the physical file has 3 names: file1 and two others.

If you only rm file1, the other 2 names still exist, and users can still access the physical file using these 2 names.

To find out all hard links to file1, use this command.
$ find /home -xdev -samefile file1
/home/peter/file1
/home/peter/tmp/file3
/home/peter/file2


Note that we specified /home as the search starting point. You should replace /home with the mount point for the filesystem in which your file1 was created. (This is likely to be either /home or / for files in your home directory.)

The reason for using the filesystem's mount point is that hard links are restricted to reside in the same filesystem as the physical file. This means that file2 and file3 must be in the same filesystem as file1. Therefore, to find ALL hard links to a file, you must start search at the mount point of the filesystem.

The -xdev option instructs find NOT to traverse directories in other filesystems.

To find and delete all hard links to a file:
$ find /home -xdev -samefile file1 | xargs rm


An alternative (and slightly more complicated) method is by using inodes. An inode is a data structure assigned to a physical file that contains all its meta-information except the file's name(s).

All hard links to a physical file share the same inode, and have the same inode id number. Therefore, if you know the inode number of a file, you can find all hard links to the file by searching for files with the same inode number.

To display a file's inode number, use ls -i:

$ ls -li file1
2655341 -rw-r--r-- 3 peter peter 0 2008-09-02 19:09 file1


The first column in the above listing shows the file's inode number.

Now that you know the inode number of file1, you can use the find command to search for all files that have the same inode number:

$ find /home -xdev -inum 2655341
/home/peter/file1
/home/peter/tmp/file3
/home/peter/file2


To delete all hard links to the physical file:
$ find /home -xdev -inum 2655341 | xargs rm 

19 comments:

Matt Di Pasquale said...

find: -samefile: unknown option

i just got a new macbook. leopard. do i need to install some kind of developer tools? what's the -xdev

Peter Leung said...

Matt

Looks like the -samefile option is not supported by the version of the "find" command.

Please try the other method mentioned in the blog: -inum (instead of -samefile).

The -xdev makes sure that the search is restricted to the same filesystem.

Anonymous said...

Good article. I'm a Windows user, using rsync to take regular backups from one NTFS volume, to another one. I was using the --link-dest parameter, which is meant to create links for unchanged files (instead of re-copying them). It didn't seem to be working, then I realized that it was creating hard links - which looked to me like normal files. It took some time to research the difference bwteen Linux hard & soft links, and Windows (NTFS) hard links, soft links, and shortcuts. The final piece of the puzzle was to see how to *identify* the hard links, on my destination (NTFS) volume, using Linux and (seperately) Windows. Your article solved the Linux part of that.

Anonymous said...

Thanks mate !! Really useful article

Unknown said...
This comment has been removed by the author.
Unknown said...

Hi, very useful post, I just learned the -inum argument.

You could do it in 1 command :
find -inum "DIRECTORIES" `ls -i "FILENAME"| awk '{print $1}'`

Well, it can be confusing :)

Anonymous said...

When deleting all the hard links to a file (which includes the file itself, because it's just another name for the file after all), instead of doing:

$ find /home -xdev -samefile file1 | xargs rm

Do this instead so it handles file names that contain white-space (otherwise they will not be deleted):

$ find /home -xdev -samefile file1 -print0 | xargs -0 rm

Or even better (if your version of find supports it - a modern version of find in Linux does), do it all within find itself:

$ find /home -xdev -samefile file1 -exec rm {} +

Anonymous said...

this is why I LOVE linux... so many hidden gems in little programs (most don't get used by us novices or likely even experts lose track of all the great tools.)
I learned the xargs options, but did know about find's new ability to execute based on what it finds (and use all the time).
Thanks everyone for a great article and comments that I can learn from.

maveric213 said...

doing

find /home -type f -printf "%i@%p\n"

will leave you with a list of all files an their coressponding inode number.

so by sorting this list

sort -n

you can easly identify which file has hardlinks and how they are grouped.

Unknown said...

How do I delete all except 1 of the hardlinks?

Slacker said...

find /home -xdev -samefile file1 | xargs ls -l

it will give you the location of every hard link in a list.

Delete however many you wish.

Anonymous said...

To find all files which have hard links:

find /mountpoint -type f -links +1

Anonymous said...

Thank you for the information

Anonymous said...

Don't use |xargs rm when you just want to delete all but one hardlink, use -exec rm {} \; for that

anonymous said...

Nice article, thanks.

However some examples demonstrate worthless use of `xargs`: to delete a file with `find` just pass "-delete" (no "-exec" needed). To print deleted files add "-print" option. See find(1) i.e. `man find` to learn more about other options.

Anonymous said...

If one directory is a symbolic link to another directory, all the files in the first directory will have the same inode number as the files in the second directory leading one to think they are hard linked so pay attention to the hard link number in the ls result to avoid that confusion.

MonoTovarisj said...

So how would I go about making a bash script where by giving one file as argument, the bash script will list all hardlinks and wait for confirmation before deleting it?

Unknown said...

Long Path Fixer presents you with a simple list of files and folders in the current directory (including "hidden" files and folders). You can drag and drop files or folders onto it and it will navigate directly to path of whatever you dropped.

Richard Varda said...

LongPathTool helps you to delete long path files.