dasfex
dasfex

Reputation: 1260

How to find all symlinks to a file?

This is my hierarchy:

aaaaaaaa
|_q
  |_a.txt
|_w
  |_l1
  |_l2

l1 and l2 are symlinks to a.txt. I run this code to find all symlinks to a.txt in the /aaaaaaaa:

find ~/aaaaaaaa/ -exec ls -a {} ';' | grep '/home/khodor/aaaaaaaa/q/a.txt'

And it obviously doesn't work, cause I must compare realpath of file with path of a.txt. In what way I should do this?

Upvotes: 4

Views: 1776

Answers (3)

oguz ismail
oguz ismail

Reputation: 50750

If you have GNU/BSD find just use -samefile primary.

$ find -L ~/aaaaaaaa/ -samefile ~/aaaaaaaa/q/a.txt 
/home/oguz/aaaaaaaa/q/a.txt
/home/oguz/aaaaaaaa/w/l2
/home/oguz/aaaaaaaa/w/l1

Upvotes: 9

Freddy
Freddy

Reputation: 4688

Using find with -type l to search for symbolic links:

find aaaaaaaa -type l -exec sh -c '
  for i; do
    printf "%s -> %s\n" "$i" "$(readlink -f "$i")"
  done
' sh {} +

The shell script prints link path and canonical path of the symlink using readlink -f (but you could also use realpath instead):

Example output:

aaaaaaaa/w/l1 -> /home/khodor/aaaaaaaa/q/a.txt
aaaaaaaa/w/l2 -> /home/khodor/aaaaaaaa/q/a.txt

Use grep to filter the result using the absolute path, e.g.

find aaaaaaaa -type l -exec sh -c '
  for i; do
    printf "%s -> %s\n" "$i" "$(readlink -f "$i")"
  done
' sh {} + | grep '/home/khodor/aaaaaaaa/q/a.txt$'

Note the $ at the end of the pattern to match the end of the line.

Upvotes: 1

vdavid
vdavid

Reputation: 2544

referenceid=$(stat -Lc '%d-%i' /home/khodor/aaaaaaaa/q/a.txt)
find ~/aaaaaaaa/ -type l -print0 | while IFS= read -r -d '' filename
do
  if [ "$(stat -Lc '%d-%i' "$filename")" = "$referenceid" ]
  then
    printf -- '%s\n' "$filename"
  fi
done

This initially gets a unique ID for a base file, e.g. /home/khodor/aaaaaaaa/q/a.txt. The ID is computed from the device ID and the inode, using stat.

Then it parses your folder using file, limited to symbolic links (thanks to -type l), and for each filename it gets the device ID and inode using stat again, using its -L option that dereferences the link before fetching the ID.

For each device ID and inode that matches the reference ID, it prints the filename.

Upvotes: 1

Related Questions