Determining if a file is a hard link or symbolic link?
Jim's answer explains how to test for a symlink: by using test
's -L
test.
But testing for a "hard link" is, well, strictly speaking not what you want. Hard links work because of how Unix handles files: each file is represented by a single inode. Then a single inode has zero or more names or directory entries or, technically, hard links (what you're calling a "file").
Thankfully, the stat
command, where available, can tell you how many names an inode has.
So you're looking for something like this (here assuming the GNU or busybox implementation of stat
):
if [ "$(stat -c %h -- "$file")" -gt 1 ]; then
echo "File has more than one name."
fi
The -c '%h'
bit tells stat
to just output the number of hardlinks to the inode, i.e., the number of names the file has. -gt 1
then checks if that is more than 1.
Note that symlinks, just like any other files, can also be linked to several directories so you can have several hardlinks to one symlink.
An example:
$ touch f1
$ ln f1 f2
$ ln f1 f3
$ ln -s f1 s1
$ ln -s f2 s2
$ ln -s ./././f3 s3
$ ln -s s3 s4
$ ln s4 s5
$ ls -li
total 0
10802124 -rw-r--r-- 3 stephane stephane 0 Nov 12 19:55 f1
10802124 -rw-r--r-- 3 stephane stephane 0 Nov 12 19:55 f2
10802124 -rw-r--r-- 3 stephane stephane 0 Nov 12 19:55 f3
10802345 lrwxrwxrwx 1 stephane stephane 2 Nov 12 19:56 s1 -> f1
10802346 lrwxrwxrwx 1 stephane stephane 2 Nov 12 19:56 s2 -> f2
10802347 lrwxrwxrwx 1 stephane stephane 8 Nov 12 19:56 s3 -> ./././f3
10802384 lrwxrwxrwx 2 stephane stephane 2 Nov 12 19:56 s4 -> s3
10802384 lrwxrwxrwx 2 stephane stephane 2 Nov 12 19:56 s5 -> s3
The f1
, f2
and f3
directory entries are the same file (same inode: 10802124, you'll notice the number of links is 3). They are hard links to the same regular file.
s4
and s5
are also the same file (10802384). They are of type symlink, not regular. They point to a path, here s3
. Because s4
and s5
are entries of the same directory, that relative path s3
point to the same file (the one with inod 10802347) for both.
If you do a ls -Ll
, that is asking to get file information after resolving symlinks:
$ ls -lLi
total 0
10802124 -rw-r--r-- 3 stephane stephane 0 Nov 12 19:55 f1
10802124 -rw-r--r-- 3 stephane stephane 0 Nov 12 19:55 f2
10802124 -rw-r--r-- 3 stephane stephane 0 Nov 12 19:55 f3
10802124 -rw-r--r-- 3 stephane stephane 0 Nov 12 19:55 s1
10802124 -rw-r--r-- 3 stephane stephane 0 Nov 12 19:55 s2
10802124 -rw-r--r-- 3 stephane stephane 0 Nov 12 19:55 s3
10802124 -rw-r--r-- 3 stephane stephane 0 Nov 12 19:55 s4
10802124 -rw-r--r-- 3 stephane stephane 0 Nov 12 19:55 s5
You'll find they all resolve to the same file (10802124).
You can check if a file is a symlink with [ -L file ]
. Similarly, you can test if a file is a regular file with [ -f file ]
, but in that case, the check is done after resolving symlinks.
hardlinks are not a type of file, they are just different names for a file (of any type).
Using the -h
and -L
operators of the test
command:
-h file
true if file is a symbolic link
-L file
true if file is a symbolic link
http://www.mkssoftware.com/docs/man1/test.1.asp
According to this SO thread, they have the same behavior, but -L
is preferred.