I frequently move directory trees to other locations or copy their tarballs to other machines, and I would like to have a method to check whether any symlinks in a directory tree A point to locations outside of A since these will be broken in the moved / copied directory.
5 Answers
You want a program called realpath
, used in conjunction with find
.
E.g.:
find . -type l -exec realpath {} \; | grep -v "^$(pwd)"

- 39,666
- 4
- 75
- 104
-
1The incantation you provide only reports the offending target location, not the symlink that points to it. As such I have removed my acceptance. Please see my "answer" below: http://unix.stackexchange.com/a/308899/24044 and if you are happy with it (or improve it) I will delete my "answer" and accept your question again. – Marcus Junius Brutus Sep 09 '16 at 16:09
I had to tweak a little the answer given by @bahamat to make it work.
The version provided simply reported the offending absolute location but not the symlink that points to it.
Here's what I used (I am sure it can be improved):
for f in $(find . -type l ); do echo -n $(realpath $f) && echo -n "|" && echo $f ; done | grep -v "^$(pwd)" | cut -d \| -f 2

- 4,587
- 11
- 44
- 65
-
I found this to be the most useful script:
for f in $(find . -type l); do echo $(realpath -m -q $f) '<-' $f; done | grep-v "^$(pwd)"
(most notably-m
and-q
which filters out broken and non-external links) – Adam Lindberg Jan 19 '17 at 13:50
With zsh:
cd -P -- "$dir"
for i (**/*(ND@)) [[ $i:A = $PWD/* ]] || [[ $i:A = $PWD ]] || print -r -- "$i => $i:A"
Now, if the directory is /foo
and you have /foo/bar
that's a symlink to /foo/baz
, that's a link whose target is in /foo, but once moved, the link will still be broken, so you may want also to match symlinks to absolute paths.
But even then, a bar => ../foo/baz
in /foo
would be an issue (false negative), so would a a => b
where b
is a symlink outside the tree (false positive, depending on how you want to look at it)

- 544,893
Use bindfs to create another view of that directory tree.
mkdir /tmp/view
bindfs /some/directory /tmp/view
Then use the symlinks utility (shipped by many distributions, or compile it from source) to detect cross-filesystem links.
symlinks -r /tmp/view | sed -n 's/^\(absolute\|other_fs\): //p'
(Note that parsing the output assumes that your symbolic links and their targets do not contain newlines, nor do paths to symbolic links contain the substring ->
.) That same utility can also convert absolute symlinks to relative (but you'd want to do that from the original location).

- 829,060
GNU coreutils provedes realpath
, which resolves symlinks. With this, you could compare each symlink's target to the current working directory with something like:
#!/bin/bash
find . | while read filename
do
if realpath $filename | grep -E "^$PWD" > /dev/null
then
echo 'this file is safe'
else
echo 'this file links externally'
fi
done

- 231
- 1
- 6
-
1Several problems: no
-type l
, no-r
option toread
, IFS not sanitized forread
,$filename
not quoted,$PWD
treated as a regular expression, paths with newline characters not accounted for,/foobar
would be matched for$PWD
== "/foo" – Stéphane Chazelas Oct 04 '12 at 21:38