10

How do I (recursively) detect all symlinks in a directory that identify their target in an absolute as opposed to in a relative way?

Since these links are very likely to break when an entire directory tree is moved I would like to have a way of identifying them.

Even relative links may break if the directory tree is moved (if they happen to point outside the root of the directory tree), but I think this is addressed in this question.

Marcus Junius Brutus
  • 4,587
  • 11
  • 44
  • 65

2 Answers2

18

To find absolute links, you can use find's -lname option if your find supports that (it's available at least in GNU find, on FreeBSD and macOS):

find . -type l -lname '/*'

This asks find to print the names of files which are symbolic links and whose content (target) matches /* using shell globbing.

Strictly speaking, POSIX specifies that absolute pathnames start with one / or three or more /; to match that, you can use

find . -lname '/*' ! -lname '//*' -o -lname '///*'

On what systems is //foo/bar different from /foo/bar? has more details on that.

(Thanks to Sato Katsura for pointing out that -lname is GNU-specific, to fd0 for mentioning that it's actually also available on at least FreeBSD and macOS, and to Stéphane Chazelas for bringing up the POSIX absolute pathname definition.)

Stephen Kitt
  • 434,908
7

You may find the symlinks utility useful:

$ symlinks -r .
other_fs: /home/chazelas/test/bin -> /bin
dangling: /home/chazelas/test/DIR/foo -> foo
dangling: /home/chazelas/test/blah -> not-here
absolute: /home/chazelas/test/chazelas -> /home/chazelas

And can fix the links for you. Here with -t to tell what it would do:

$ symlinks -rct .
other_fs: /home/chazelas/test/bin -> /bin
dangling: /home/chazelas/test/DIR/foo -> foo
dangling: /home/chazelas/test/blah -> not-here
absolute: /home/chazelas/test/chazelas -> /home/chazelas
changed:  /home/chazelas/test/chazelas -> ../../chazelas