vsh@etnibsd.UUCP (Steve Harris) (10/18/90)
Here is a perl script to trace symbolic links. On our network, with all its NFS mount points and symlinks to get from one place to another, a file path often has several symlinks in it. "ls -l" will tell you if the final component is a symlink, but not if any of the internal pathname components are, nor will it tell you if the thing pointed to is itself a symlink. Slinky gives you all this info. It's also my first script to use splice. Neat stuff! Any suggestions/improvements/bug-fixes welcome. =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- cut here =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- #! /bin/sh # This is a shell archive, meaning: # 1. Remove everything above the #! /bin/sh line. # 2. Save the resulting text in a file. # 3. Execute the file with /bin/sh (not csh) to create: # slinky.pl # This archive created: Wed Oct 17 14:09:58 1990 export PATH; PATH=/bin:/usr/bin:$PATH echo shar: "extracting 'slinky.pl'" '(2968 characters)' if test -f 'slinky.pl' then echo shar: "will not over-write existing file 'slinky.pl'" else sed 's/^ X//' << \SHAR_EOF > 'slinky.pl' X#!/usr/bin/perl X X######################################################################## X# X# slinky.pl -- a symbolic link walker X# X# For each file name on the command line, this script will resolve X# all symbolic links in the path. If -v (verbose) option, each step X# of the symlink resolution will be displayed. Uses splice statement. X# X# outline of program (for a single path): X# X# split the path into array @path X# set initial $offset to 1 X# loop: while (not too many links) { X# join the first [0..$offset] components into $path X# if ($path is a link) { X# read the link into $link X# if ($link is absolute) { X# splice $link into start of @path X# set $offset to 1 (re-start at beginning of path) X# } else { X# splice $link into middle of @path X# } X# } elsif ($path exists) { X# increment $offset X# } else { X# set $notexist flag and break out of loop X# } X# } X# X######################################################################## X X X# setup program path and name, and usage strings X@prog = split(/\//, $0); X$prog = $prog[$#prog]; X$ustr = "usage: $prog [-Uv] file...\n"; X$Ustr =<<EOF; Xwhere X -v verbose (show each step of symlink resolution) X -U usage (show this message) XEOF X Xsub usage { X print STDERR $ustr; X print STDERR $Ustr if $_[0]; X exit 1; X} X Xwhile ($_ = $ARGV[0], /^-/) { X shift; X if ($_ eq '--') { last; } X if (/v/) { $verbose++; next; } X if (/U/) { &usage(1); } X &usage(); X} X X&usage() if $#ARGV < 0; X X$maxlinks = 32; Xwhile ($#ARGV >= 0) { X $_ = shift; X s!^!./! unless m!^\.{0,2}/!; # relative pathname: start with "./" X print "$_:\n" if $verbose; X @path = split(/\//, $_); X $notexist = 0; X $offset = 1; X for ($nlinks=0; $nlinks<$maxlinks; ) { X last if $offset > $#path; # done??? X $path = join('/', @path[0..$offset]); # get path head X if ( -l $path ) { # it's a link: X $nlinks++; X printf "%5d:\t", $nlinks if $verbose; X &printit($offset-1, $offset) if $verbose; X print " -> " if $verbose; X $link = readlink($path); # get the link X @tmp = split(/\//, $link); X if ($link =~ m!^/!) { X # link is absolute: replace @path head X splice(@path,0,$offset+1,@tmp); X &printit(0,$#tmp,1) if $verbose; X $offset = 1; # and start at top X } else { X # link is relative: replace @path middle X splice(@path,$offset,1,@tmp); X &printit($offset-1,$offset+$#tmp) if $verbose; X } X print "\n" if $verbose; X } elsif ( -e $path ) { # not a link X $offset++; # do next component of @path X } else { X $notexist = 1; # does not exist X last; X } X } X if ($nlinks >= $maxlinks) { X die "tracelinks: too many links, aborted"; X } X print "$_"; X print " -> ", join('/',@path) if $nlinks; X print " (does not exist)" if $notexist; X print "\n"; X print "\n" if $verbose; X} X Xsub printit { X local($d1,$d2,$abs) = @_; X if ($abs) { X print "{/"; X } else { X print join('/', @path[0..$d1]); X print "/{"; X } X print join('/', @path[$d1+1..$d2]), "}"; X print "/", join('/', @path[$d2+1..$#path]) if $d2 < $#path; X} SHAR_EOF if test 2968 -ne "`wc -c < 'slinky.pl'`" then echo shar: "error transmitting 'slinky.pl'" '(should have been 2968 characters)' fi fi exit 0 # End of shell archive =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- cut here =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- -- Steve Harris - Eaton Corp. - Beverly, MA - uunet!etnibsd!vsh