Take the 2-minute tour ×
Unix & Linux Stack Exchange is a question and answer site for users of Linux, FreeBSD and other Un*x-like operating systems.. It's 100% free, no registration required.

In Linux, what is the best way to find all symbolic links that point to a given file (regardless of whether the symlink is relative or absolute)? I realize this will require scanning the whole filesystem.

share|improve this question

2 Answers 2

up vote 4 down vote accepted

GNU find has the -samefile test. According to the man page:

-samefile name
    File refers to the same inode as name. When -L is in 
    effect, this can include symbolic links.
$ find -L / -samefile /path/to/file

This will find all links to /path/to/file, which includes hard links and the file itself. If you only want symlinks, you can individually test the results of find (test -L).

You should read up on what the effects of -L are and ensure that it won't cause you any problems with your search.

Note: While the documentation says it looks for files with the same inode number, it does appear to work across filesystems.

e.g. /home and /tmp are separate filesystems

$ touch ~/testfile
$ ln -s ~/testfile /tmp/foo
$ ln -s /tmp/foo /tmp/bar
$ mkdir /tmp/x
$ ln -s ~/testfile /tmp/x/baz
$ find -L /tmp -samefile ~/testfile
/tmp/bar
/tmp/foo
/tmp/x/baz

Note how this is returning /tmp/bar, which is a symlink to /tmp/foo, which is a symlink to ~/testfile. If you only wanted to find direct symlinks to your target file, this wont work.

share|improve this answer

Perhaps the shortest way would be:

target="/usr/bin/firefox"    # change me
dir="/usr/bin"               # change me
realtarget="$(realpath "$target")"
for file in $(find "$dir" -print); do
    realfile="$(realpath "$file")"
    test "$realfile" = "$realtarget" && echo "$file"
done

But it's not very efficient.

If you don't have realpath, install it, e.g. apt-get install realpath. You could also use stat -N or ls -l or pwd -P to emulate realpath, but those ways are harder.

Also, the above example won't handle file names with spaces in it properly. Here's a better way to do it. Note that IFS=$'\n' requires bash or zsh.

OIFS="$IFS"
IFS=$'\n'
target="/usr/bin/firefox"    # change me
dir="/usr/bin"               # change me
realtarget="$(realpath "$target")"
find "$dir" -print | while read -r file; do
    realfile="$(realpath "$file")"
    test "$realfile" = "$realtarget" && echo "$file"
done
IFS="$OIFS"
share|improve this answer

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

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