SUMMARY: Finding Broken Links

From: Sumair Mahmood <Sumair.Mahmood_at_qlogic.com>
Date: Tue Apr 30 2002 - 12:15:47 EDT
QUESTION:
=========

I have a number of broken symbolic links on the file systems of
computers which I manage.  I know I can find all of the symbolic
links in a given filesystem using the following :

	(1) ls -l | grep '^l'
	(2) find /dir -type l -exec ls -l {} \;

Is there a way, I wonder, to 'follow' a link to test to see if it
is valid? 'ls -L' isn't reporting any errors for my broken links.
I would like to throw together a Bourne script to automate the
process of finding and deleting dangling links.

P.S.  I wish I did, but I don't know Perl.  If we could please
	limit this discussion to Unix shell scripting, I would
	appreciate it!

ANSWERS:
========
(1)  find /dir -type l -follow
	will return "find: cannot follow symbolic link [whatever]:
	No such file or directory" for each broken link.

     - Alex Shephard

(2)  See Figure 5 at the following PDF for a csh script
	http://swexpert.com/C4/SE.C4.DEC.96.pdf

     (but really, I'd rather use perl for this job...)    :-)

     - Darren Dunham

(3)  'test -r' fails on a hanging symlink.  The /bin/sh-ism would
	be something like:

	if [ -h $fname ] && [ ! -r $fname ] ; then
	   echo "Bad symbolic link!"
	fi

     - Jay Lessert

(4) Here is a shell script to find broken links:
	----cut here----
	#!/bin/ksh
	#
	ls -ld * | grep '^l' | awk '{print $9}' > /tmp/linktmp.$$
	for x in `cat /tmp/linktmp.$$`
	do
	      if [ ! -e $x ]
	         then
	         echo "bogus link: $x"
	      fi
	done
	----cut here----

     and here is one in Perl:

	----cut here----
	#!/usr/local/bin/perl
	use File::Find;
	find( \&wanted, '.' );
	sub wanted {
		-l and not -e and print "bogus link: $File::Find::name\n";
	}
	----cut here----
     - Tim Fritz

(5) "test -s $file || ls -la $file" is the test you want in Bourne
	shell syntax.

     - Thomas Anders

(6) Here you go:
	for link in `find . -type l `
	do
	  cat $link > /dev/null 2> /dev/null;
	  if test $? -ne 0
	  then
	     echo $link
	  fi
	done

     - Chris Veenstra

(7) Something like:
	find /dir -type l -exec ls -l {} \; -exec cat {} \>dev/null \;
    Should throw an error for the ones that are broken

     - Jim Malloy

(8) Try this:
	for i in `ls -lc directory |awk '/^l/ {print $11}'`
	do
	  echo $i
	  if [ -r $i ]
	  then
		echo "$i exists"
	  fi
	done

     - Jaime Dela Rosa

(9) Perl exists for a reason:
	#!/usr/bin/perl -w
	use strict;
	use File::Find;

	sub wanted
	{
		my $curfil = $_;
		my $curdir = $File::Find::dir;
		if ( ! -l $curfil ) { return; }
		#Curfil is a symlink
		my $linkto = readlink($curfil);
		if ( -e $linkto ) { return; }
		#file it links to does not exist
		print "$curdir/$curfil is a broken link (pointing to $linkto)\n";
	}

	#Start of script
	my $top = shift @ARGV or die "Please provide a starting directory";

	find(\&wanted,$top);
	----------------------------
	Usage:
	link-test.pl /
	(one argument, the directroy to start the find in).

     - Thomas M. Payerle

(10) Doing this in perl, you could do the following:

	#!/usr/local/bin/perl -w
	use File::Find;
	find(\&wanted, '/dir');
	sub wanted {
		return unless -l $File::Find::name;	# Check only symbolic links
		unless (stat($File::Find::name)){	# If the file can't be stat'd
			print "Bad link for $File::Find::name\n";
		}
	}

     - Dylan Northrup
_______________________________________________
sunmanagers mailing list
sunmanagers@sunmanagers.org
http://www.sunmanagers.org/mailman/listinfo/sunmanagers
Received on Tue Apr 30 12:22:38 2002

This archive was generated by hypermail 2.1.8 : Thu Mar 03 2016 - 06:42:41 EST