35

How can I tell if two files are hard-linked from the command line? e.g. something link this:

$ ls
fileA fileB fileC

$ is-hardlinked fileA fileB
yes

$ is-hardlinked fileA fileC
no

6 Answers 6

46

On most filesystems¹, a file is uniquely determined by its inode number, so all you need to check is whether the two files have the same inode number and are on the same filesystem.

Ash, ksh, bash and zsh have a construct that does the check for you: the file equality operator -ef.

[ fileA -ef fileB ] && ! [ fileA -ef fileC ]

For more advanced cases, ls -i /path/to/file lists a file's inode number. df -P /path/to/file shows what filesystem the file is on (if two files are in the same directory, they're on the same filesystem). If your system has the stat command, it can probably show the inode and filesystem numbers (stat varies from system to system, check your documentation). If you want a quick glance of hard links inside a directory, try ls -i | sort (possibly piped to awk).

¹ All native unix filesystems, and a few others such as NTFS, but possibly not exotic cases like CramFS.

7
  • And definitely not on anything FAT-based, where it would be detected as a "cross-linked" file. Commented Nov 8, 2011 at 0:16
  • 7
    Note that fileA -ef fileB also returns 0 (success) if fileA is a symlink to fileB, or vice versa, or they both link to the same file.
    – janmoesen
    Commented Nov 8, 2011 at 16:50
  • how do you actually run the command you suggested? I tried [ .bashrc -ef .bash/.bashrc ] and variations of this but it didn't really work. Commented Jun 15, 2014 at 4:33
  • @CharlieParker [ .bashrc -ef .bash/.bashrc ] is correct. Without context, of course, I have no idea why it “didn't really work” — you could be comparing the wrong files, you could be not checking the outcome correctly, you could be using a shell without -ef, ... Commented Jun 15, 2014 at 10:49
  • 3
    @CharlieParker The command is actually [ and is a synonym of test. But man [ or man test will give you the man page of the external command, whereas just about every shell out there has a built-in command with slightly different options, so you need to look this one up in your shell's manual. Commented Jun 15, 2014 at 18:33
5
function is-hardlinked() {
    r=yes
    [ "`stat -c '%i' $1`" != "`stat -c '%i' $2`" ] && r=no
    echo $r
}
4
  • 9
    Note that this can be a false positive if the two files are on different filesystems but happen to have the same inode. You need to test the device number as well (stat -c %d). And if you're on Linux (given your stat command), your shell has the [ fileA -ef fileB ] to do all this directly. Also, your command gratuitously breaks with file names containing whitespace or \[?*, or begins with -: always put double quotes around command susbtitutions ("$(stat -c %i -- "$1")"). Commented Jan 29, 2013 at 15:41
  • 3
    Why would you use a bunch of cumbersome but portable constructs, and then the abjectly non-portable function keyword with a function name that (on account of containing a dash) violates POSIX conventions on allowed names? Commented May 19, 2017 at 22:25
  • You forgot to quote your $1 and $2. You might also want to use the $() syntax instead of backticks because the brackets make it clear where the command begins and where it ends and nesting is simpler.
    – josch
    Commented Dec 30, 2018 at 16:08
  • @Gilles'SO-stopbeingevil', ['s -ef checks whether the files are the same after symlink resolution, while GNU stat by default gets information from the symlink itself, so it's not equivalent. You can't use ['s -ef to check that two symlink files are hard linked to each other. GNU find's -samefile can be used instead or approaches based on various implementations of stat (provided you get both device and inode number as you said). Commented Jun 1, 2022 at 11:12
3

As the first poster suggest, you can write a script based on something like this on Linux:

stat -c '%i' fileA fileB fileC
2
  • 7
    This isn't enough: you'll get the same number for the two files if are on different filesystems but happen to have the same inode. You need to test the device number as well (stat -c %d). And if you're on Linux (given your stat command), your shell has the [ fileA -ef fileB ] to do all this directly. Commented Jan 29, 2013 at 15:42
  • @Gilles'SO-stopbeingevil', ['s -ef checks whether the files are the same after symlink resolution, while GNU stat by default gets information from the symlink itself, so it's not equivalent. You can't use ['s -ef to check that two symlink files are hard linked to each other. GNU find's -samefile can be used instead or approaches based on various implementations of stat (provided you get both device and inode number as you said). Commented Jun 1, 2022 at 11:11
3

With GNU find(1) version 4.2.11 or newer you can also use this:

if [ yes = "$(find fileA -prune -samefile fileB -printf yes)" ]; then
    echo yes
else
    echo no
fi

If fileA is the same file as fileB then find will print "yes" and the condition becomes true.

In contrast to using the file equality operator -ef this will spawn a new process.

-3

You can do this very simply with the built-in bash operator -ef:

[[ file1 -ef file2 ]] && echo Same

If the condition evaluates to true (file1 and file2 are the same), then it prints "Same". Otherwise, nothing is output.

3
  • 1
    This test will also be true if file1 is a symbolic link to file2, or the other way around. I don't really see a difference between this and the accepted answer (which has the same issue).
    – Kusalananda
    Commented Jan 9, 2021 at 23:13
  • @kusalananda Nope, docs specifically say it compares inode numbers: gnu.org/software/bash/manual/html_node/…
    – Bill
    Commented Jan 9, 2021 at 23:16
  • 1
    Sure, but it resolves symbolic links first. I suggest you test it.
    – Kusalananda
    Commented Jan 10, 2021 at 5:32
-4

theres is other solution in the sh shell :

#!/bin/sh
file1='readlink $1'
file2='readlink $2'
if [ file1==file2 -o file2==file1 ]
then
echo "the files are linked with strong link"
else
echo "the files are not linked"
fi

the readlink give us the right to copy the inode into a string variable and compare it with other string variable . (two files have a string link have the same inode).

1
  • 1
    Consider updating your answer with code that is actually working. Note that your code will never call readlink, will not expand $1 nor $2, and will treat file1==file2 as one string, and file2==file1 as another, and both are always true (as they are non-empty strings). Additionally, readlink deals with symbolic links, not hard links.
    – Kusalananda
    Commented Jun 1, 2022 at 11:13

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .