[comp.lang.perl] following symbolic links

lwall@jpl-devvax.JPL.NASA.GOV (Larry Wall) (03/17/90)

In article <1678@zipeecs.umich.edu> bguthy@dip.eecs.umich.edu (Bala S. Guthy) writes:
: Lately I find myself doing things like 
: %ls -ld /usr/prog
: 
: and after finding that this is linked to /n/node1/bin, I'd do
: 
: %ls -ld /n/node1/bin
: 
: and so on...
: until I get to my destination directory/file. Is there some way to
: do this easily, may be a program that prints all the intermediate directories
: that are used in getting to a file, across nfs mounts and symbolic links.

Ok, I just whipped up a little program called "sl" (for showlinks) that
does what you want, in a hopefully convenient format:

$ sl dts/libg/dts.h

dts/libg/dts.h:
dts/libg -> lib_incl_global
    lib_incl_global/dts.h -> SRC/dts.h
                    SRC -> /u/dts/dts/lib_incl_global
/u/dts -> /u8/dts
/u8/dts/dts/lib_incl_global/dts.h

$ sl /usr/lib/news/compress

/usr/lib/news/compress:
/usr/lib/news -> ../local/lib/news
     local/lib/news/compress -> /usr/ucb/compress
/usr/ucb/compress

$ sl D M P

D:
D -> src/dist/Todo
src -> /s/lwall/src
/s/lwall/src/dist/Todo

M:
M -> src/dist/mcon/Todo
src -> /s/lwall/src
/s/lwall/src/dist/mcon/Todo

P:
P -> src/patch/Todo
src -> /s/lwall/src
/s/lwall/src/patch/Todo

$ sl bin/makedist

bin/makedist:
bin -> vbin
vbin/makedist -> ../src/dist/kit/makedist
src -> /s/lwall/src
/s/lwall/src/dist/kit/makedist

$ sl /u/sfoc/lwall/bin/makedist

/u/sfoc/lwall/bin/makedist:
/u/sfoc -> /u4/sfoc
/u4/sfoc/lwall/bin -> vbin
               vbin/makedist -> ../src/dist/kit/makedist
               src -> /s/lwall/src
/s/lwall/src/dist/kit/makedist

It is, of course, written in Perl.  Translation to C is left as an
exercise for the reader.  :-)

Larry Wall
lwall@jpl-devvax.jpl.nasa.gov

#!/bin/sh
: make a subdirectory, cd to it, and run this through sh.
echo 'If this kit is complete, "End of kit" will echo at the end'
echo Extracting sl
sed >sl <<'!STUFFY!FUNK!' -e 's/X//'
X#!/usr/bin/perl
X
Xdie "Usage: sl [filenames]\n" unless @ARGV;
X
X$| = 1;
Xchop($cwd = `pwd`) || die "Can't find current directory: $!\n" if $#ARGV > 0;
X
Xprint "\n";
Xforeach $name (@ARGV) {
X    @indent = ();
X    print "$name:\n";
X    @path = split(m;/;, $name);
X    if (@path && $path[0] eq '') {
X	chdir '/';
X	shift @path;
X	print '/';
X	$indent = 1;
X    }
X    while (@path) {
X	$elem = shift @path;
X	$new = readlink($elem);
X	if (defined $new) {
X	    print "$elem -> $new\n";
X	    $new =~ s!^\./!!;
X	    unshift(@path,split(m;/;, $new));
X	    if (@path && $path[0] eq '') {
X		chdir '/';
X		shift @path;
X		print '/';
X		$indent = 1;
X		@indents = ();
X	    }
X	    elsif (@path && @indents && $path[0] eq '..') {
X		$indent = pop(@indents);
X		chdir '..' || die "\n\nCan't chdir to ..: $!\n";;
X		shift @path;
X		print "\t" x ($indent / 8), ' ' x ($indent % 8);
X	    }
X	    else {
X		print "\t" x ($indent / 8), ' ' x ($indent % 8);
X	    }
X	}
X	else {
X	    print $elem;
X	    push(@indents,$indent);
X	    $indent += length($elem) + 1;
X	    if (@path) {
X		print '/';
X		chdir $elem || die "\n\nCan't chdir to $elem: $!\n";;
X	    }
X	}
X    }
X    print "\n\n";
X    $indent = 0;
X    chdir $cwd || die "Can't cd back: $!\n" if $cwd ne '';
X}
!STUFFY!FUNK!
echo ""
echo "End of kit"
: I do not append .signature, but someone might mail this.
exit