I run

ln /a/A /b/B

I would like to see at the folder a where the file A points to by ls.

How can you see the actual hard link by ls?

link|improve this question

1  
I think this belongs on serverfault.com – chakrit Jul 25 '09 at 9:44
3  
Or on superuser.com? It isn't really dealing with a 'server' issue, merely a general POSIX system. – Douglas Leeder Jul 25 '09 at 11:43
feedback

migrated from stackoverflow.com Jul 25 '09 at 22:53

This question came from our site for professional and enthusiast programmers.

5 Answers

up vote 17 down vote accepted

You can find inode number for your file with

ls -i

and

ls -l

shows references count (number of hardlinks to particular inode) after you found inode number, you can search for all files with same inode:

find . -inum NUM

will show filenames for inode NUM in current dir (.)

link|improve this answer
1  
+1 because you beat me to it – eyelidlessness Jul 25 '09 at 10:03
No, +1 'cause it's the best answer :-) – Pax Jul 25 '09 at 10:27
To be fair, the only thing that distinguished it from mine was the -i flag at the time I upvoted. – eyelidlessness Jul 25 '09 at 18:34
feedback

There isn't really a well-defined answer to your question. Unlike symlinks, hardlinks are indistinguishable from the original file. Filenames in directories are just references to an inode (which contains the file contents and file attributes). Creating a hard link creates another reference to the same inode. These references are unidirectional (in typical filesystems, at least) -- the inode only keeps a reference count.

This means that the only way to find the other references to a given inode is to exhaustively search over the file system checking which files refer to the inode in question. You can use 'test A -ef B' from the shell to perform this check.

link|improve this answer
2  
That means that there is no such thing as a hard link to another file, as the original file is also a hard link; hard links point to a location on disk. – jtbandes Jul 26 '09 at 0:03
feedback

UNIX has hard links and symbolic links (made with "ln" and "ln -s" respectively). Symbolic links are simply a file that contains the real path to another file and can cross filesystems.

Hard links have been around since the earliest days of UNIX (that I can remember anyway, and that's going back quite a while). They are two directory entries that reference the exact same underlying data. The data in a file is specified by its inode. Each file on a file system points to an inode but there's no requirement that each file point to a unique inode - that's where hard links come from.

Since inodes are unique only for a given filesystem, there's a limitation that hard links must be on the same filesystem (unlike symbolic links). Note that, unlike symbolic links, there is no privileged file - they are all equal. The data area will only be released when all the files using that inode are deleted (and all processes close it as well, but that's a different issue).

You can use the "ls -i" command to get the inode of a particular file. You can then use the "find <filesystemroot> -inum <inode>" command to find all files on the filesystem with that given inode.

Here's a script which does exactly that. You invoke it with:

findhardlinks ~/jquery.js

and it will find all files on that filesystem which are hard links for that file:

pax@daemonspawn:~# ./findhardlinks /home/pax/jquery.js
Processing '/home/pax/jquery.js'
   '/home/pax/jquery.js' has inode 5211995 on mount point '/'
       /home/common/jquery-1.2.6.min.js
       /home/pax/jquery.js

Here's the script.

#!/bin/bash
if [[ $# -lt 1 ]] ; then
    echo "Usage: findhardlinks <fileOrDirToFindFor> ..."
    exit 1
fi

while [[ $# -ge 1 ]] ; do
    echo "Processing '$1'"
    if [[ ! -r "$1" ]] ; then
        echo "   '$1' is not accessible"
    else
        numlinks=$(ls -ld "$1" | awk '{print $2}')
        inode=$(ls -id "$1" | awk '{print $1}' | head -1l)
        device=$(df "$1" | tail -1l | awk '{print $6}')
        echo "   '$1' has inode ${inode} on mount point '${device}'"
        find ${device} -inum ${inode} 2>/dev/null | sed 's/^/        /'
    fi
    shift
done
link|improve this answer
@pax: There seems to be a bug in the script. I start it by . ./findhardlinks.bash while being in OS X's Zsh. My current window in Screen closes. – Masi Jul 25 '09 at 16:31
1  
@Masi The issue is your initial . (same as the source command). That causes the exit 1 command to exit your shell. Use chmod a+x findhardlinks.bash then execute it with ./findhardlinks.bash or use bash findhardlinks.bash – njsf Jul 25 '09 at 23:08
Please, see my reply to your answer at superuser.com/questions/12972/to-see-hardlinks-by-ls/… – Masi Jul 26 '09 at 16:42
To do this programmatically, it's probably more resilient if you use this instead: INUM=$(stat -c %i $1). Also NUM_LINKS=$(stat -c %h $1). See man stat for more format variables you can use. – Joe Jan 3 at 20:12
feedback
ls -l

The first column will represent permissions. The second column will be the number of sub-items (for directories) or the number of paths to the same data (hard links, including the original file) to the file. Eg:

-rw-r--r--@    2    [username]    [group]    [timestamp]     HardLink
-rw-r--r--@    2    [username]    [group]    [timestamp]     Original
               ^ Number of hard links to the data
link|improve this answer
feedback

Based on the 'findhardlinks' script (renamed it to: hard-links), this is what I have refactored and made it work.

Output:

./hard-links /root

Item: /[10145] = /root/.profile
-> /proc/907/sched
-> /<some-where>/.profile

Item: /[10144] = /root/.tested
-> /proc/907/limits
-> /<some-where else>/.bashrc
-> /root/.testlnk

Item: /[10144] = /root/.testlnk
-> /proc/907/limits
-> /<another-place else>/.bashrc
-> /root/.tested

# cat ./hard-links
#!/bin/bash
oIFS="${IFS}"; IFS=$'\n';
xPATH="${1}";
xFILES="`ls -al ${xPATH}|egrep "^-"|awk '{print $9}'`";
for xFILE in ${xFILES[@]}; do
  xITEM="${xPATH}/${xFILE}";
  if [[ ! -r "${xITEM}" ]] ; then
      echo "Path: '${xITEM}' is not accessible! ";
    else
      nLINKS=$(ls -ld "${xITEM}" | awk '{print $2}')
      if [ ${nLINKS} -gt 1 ]; then
        iNODE=$(ls -id "${xITEM}" | awk '{print $1}' | head -1l)
        xDEVICE=$(df "${xITEM}" | tail -1l | awk '{print $6}')
        echo -e "\nItem: ${xDEVICE}[$iNODE] = ${xITEM}";
        find ${xDEVICE} -inum ${iNODE} 2>/dev/null|egrep -v "${xITEM}"|sed 's/^/   -> /';
      fi
  fi
done
IFS="${oIFS}"; echo "";
link|improve this answer
feedback

Your Answer

 
or
required, but never shown

Not the answer you're looking for? Browse other questions tagged or ask your own question.