384

I'm trying to find all of the symlinks within a directory tree for my website. I know that I can use find to do this but I can't figure out how to recursively check the directories.

I've tried this command:

find /var/www/ -type l

… and later I discovered that the contents in /var/www are symlinks, so I've changed the command to:

find -L /var/www/ -type l

it take a while to run, however I'm getting no matches.

How do I get this to check subdirectories?

Eliran Malka
  • 15,821
  • 6
  • 77
  • 100
hafichuk
  • 10,351
  • 10
  • 38
  • 53

8 Answers8

413

This will recursively traverse the /path/to/folder directory and list only the symbolic links:

ls -lR /path/to/folder | grep '^l'

If your intention is to follow the symbolic links too, you should use your find command but you should include the -L option; in fact the find man page says:

   -L     Follow symbolic links.  When find examines or prints information
          about files, the information used shall be taken from the  prop‐
          erties  of  the file to which the link points, not from the link
          itself (unless it is a broken symbolic link or find is unable to
          examine  the file to which the link points).  Use of this option
          implies -noleaf.  If you later use the -P option,  -noleaf  will
          still  be  in  effect.   If -L is in effect and find discovers a
          symbolic link to a subdirectory during its search, the subdirec‐
          tory pointed to by the symbolic link will be searched.

          When the -L option is in effect, the -type predicate will always
          match against the type of the file that a symbolic  link  points
          to rather than the link itself (unless the symbolic link is bro‐
          ken).  Using -L causes the -lname and -ilname predicates  always
          to return false.

Then try this:

find -L /var/www/ -type l

This will probably work: I found in the find man page this diamond: if you are using the -type option you have to change it to the -xtype option:

          l      symbolic link; this is never true if the -L option or the
                 -follow option is in effect, unless the symbolic link  is
                 broken.  If you want to search for symbolic links when -L
                 is in effect, use -xtype.

Then:

find -L /var/www/ -xtype l
Mateen Ulhaq
  • 24,552
  • 19
  • 101
  • 135
ztank1013
  • 6,939
  • 2
  • 22
  • 20
  • 1
    Thanks, this would probably work however I just noticed that the contents of /var/www/ are already symlinks and this doesn't seem to recurse into those directories. – hafichuk Dec 14 '11 at 23:31
  • @hafichuk Do yo want to recursively follow symlinks too? – ztank1013 Dec 14 '11 at 23:34
  • Yes, since some of the symlinks are to other directories. I have to assume (pray) that there isn't going to be a loop. – hafichuk Dec 14 '11 at 23:36
  • The way I interpret the `-L` option is that this just wont work since it matches against the type of the file that the link points to. Thanks for highlight this from the man page, I did miss it! – hafichuk Dec 14 '11 at 23:44
  • 5
    @hafichuk see final edit in my answer (`find -L /var/www/ -xtype l`). Using `-xtype` instead of `-type` should do the trick in your find. Good Luck! – ztank1013 Dec 14 '11 at 23:52
  • 4
    Make that `ls -laR /path/to/folder | grep ^l` if you also want to process "hidden" dot folders ... – wimvds Sep 13 '13 at 09:58
  • 4
    Thank you! But this only shows the name of links but not their location. – Kostanos Mar 18 '14 at 23:08
  • 10
    in Mac OSX (10.9), `-xtype` is not available. `find . -type l` seems to be checking recursively. – amertkara May 23 '14 at 12:33
  • Works like a charm with `find (GNU findutils) 4.4.2` Just as a side note, the `xtype -l` is 'dash el' not 'dash one' the code formatting on SE makes it look like either. – eggmatters Jul 30 '15 at 17:12
  • Thank you. The first answer is the perfect thing for people like me wanting to clean dropbox of internal links. Hopefully this comment will make your answer easier to find. – KobeJohn Dec 30 '15 at 11:03
  • In case you want to find file-only symbolic links (ignoring completely directory links) do: `find -l /path/tosearch/ -xtype f` or for symlinks to all kinds of non-directory nodes: `find -l /path/tosearch/ -not -xtype d` – Marinos An Jun 14 '18 at 12:25
  • in Mac OSX (10.15.x/Catalina), the `-xtype` still not supported . The `-ls` can show detail (including target file of a symlink). For a non-sym-link dir which has 2 symlinks & 2 real files, The `find -L /var/www/ -type l -print0 -ls` shows nothing, The `find -L /var/www/ -print0 -ls` shows all 4 (2 symlinks & 2 files) & the /bar/www/ dir itself, The `find /var/www/ -type l -print0 -ls` shows 2 symlinks, The `find /var/www/ -type f -print0 -ls` shows 2 real files, The `find /var/www/ -print0 -ls` shows 4 files (2 symlinks & 2 real files) & the /bar/www/ dir itself, & `-not -type d` skips dir(s) – atErik Sep 01 '20 at 17:56
  • 1
    For one command to list them all with targets: `find -L . -type l -exec ls -l {} \;` – Zbyszek Sep 04 '20 at 15:46
375

One command, no pipes

find . -type l -ls

Explanation: find from the current directory . onwards all references of -type link and list -ls those in detail. Plain and simple...

Expanding upon this answer, here are a couple more symbolic link related find commands:

Find symbolic links to a specific target

find . -lname link_target

Note that link_target is a pattern that may contain wildcard characters.

Find broken symbolic links

find -L . -type l -ls

The -L option instructs find to follow symbolic links, unless when broken.

Find & replace broken symbolic links

find -L . -type l -delete -exec ln -s new_target {} \;

More find examples

More find examples can be found here: https://hamwaves.com/find/

Serge Stroobandt
  • 28,495
  • 9
  • 107
  • 102
  • 8
    If you're looking to be more succinct it might be worth mentioning that most versions of `find` have an `-ls` option. So `find . -type l -ls` should be the equivalent of the above. – Bratchley Aug 12 '14 at 14:29
  • 11
    This improves on the accepted answer because it also tells you where the symlinks are in the directory tree, especially important when working with the kind of complex and deep tree as is likely to have symlinks. – Jesse Crossen Nov 26 '14 at 15:20
  • Unless run as root, the command would miss any symlinks it can't get to (which may be what you want). To be thorough, use `sudo sh -c 'find / -type l -ls > /symlink.list'`: this will list all of the symlinks of the entire file system in the root-owned file /symlink.list. – Urhixidur Nov 07 '17 at 19:22
  • 5
    This answer is far more useful than the accepted one. Also, if you want to find symlinks that point to files in some directory: `find -lname '*/dir/*' -printf '%P -> %l\n'`. It worth mentioning that link_target is a pattern. – x-yuri Dec 07 '18 at 00:24
16

find already looks recursively by default:

[15:21:53 ~]$ mkdir foo
[15:22:28 ~]$ cd foo
[15:22:31 ~/foo]$ mkdir bar
[15:22:35 ~/foo]$ cd bar
[15:22:36 ~/foo/bar]$ ln -s ../foo abc
[15:22:40 ~/foo/bar]$ cd ..
[15:22:47 ~/foo]$ ln -s foo abc
[15:22:52 ~/foo]$ find ./ -type l
.//abc
.//bar/abc
[15:22:57 ~/foo]$ 
jman
  • 11,334
  • 5
  • 39
  • 61
10

To see just the symlinks themselves, you can use

find -L /path/to/dir/ -xtype l 

while if you want to see also which files they target, just append an ls

find -L /path/to/dir/ -xtype l -exec ls -al {} \;
MariusPontmercy
  • 398
  • 1
  • 5
  • 20
8

This is the best thing I've found so far - shows you the symlinks in the current directory, recursively, but without following them, displayed with full paths and other information:

find ./ -type l -print0 | xargs -0 ls -plah

outputs looks about like this:

lrwxrwxrwx 1 apache develop 99 Dec  5 12:49 ./dir/dir2/symlink1 -> /dir3/symlinkTarget
lrwxrwxrwx 1 apache develop 81 Jan 10 14:02 ./dir1/dir2/dir4/symlink2 -> /dir5/whatever/symlink2Target
etc...
siliconrockstar
  • 3,554
  • 36
  • 33
1

Kindly find below one liner bash script command to find all broken symbolic links recursively in any linux based OS

a=$(find / -type l); for i in $(echo $a); do file $i ; done |grep -i broken 2> /dev/null
linux.cnf
  • 519
  • 6
  • 7
  • 1
    Your command can be `find / -type l -exec file {} \; | grep -i broken 2>/dev/null`. Please bear in mind that you will probably have a lot of false positives. – ingroxd Jan 29 '21 at 00:39
0

You can install "symlinks" package and use the utility

symlinks -rv "/path"

    -c == change absolute/messy links to relative
    -d == delete dangling links
    -o == warn about links across file systems
    -r == recurse into subdirs
    -s == shorten lengthy links (displayed in output only when -c not specified)
    -t == show what would be done by -c
    -v == verbose (show all symlinks)

Dangling links are broken ones.

16851556
  • 255
  • 3
  • 11
-2

What I do is create a script in my bin directory that is like an alias. For example I have a script named lsd ls -l | grep ^d

you could make one lsl ls -lR | grep ^l

Just chmod them +x and you are good to go.

Alex M
  • 141
  • 2
  • 6