in reply to Following symlinks manually

I see two hard parts here: resolving relative links and avoiding loops. For resolving relative links, File::Spec's rel2abs might help; notice you can give a base directory where the relative path should start from. For avoiding loops, many OS's just keep a count and give up after some number of symlinks; you could also track specific links in a hash and stop chasing links if you end up someplace you've been before.

I'm not sure whether you care about parent directories being symlinks, too. If so, that's a third hard part, though it's certainly manageable.

Here's some code to chase symlinks and print out what it finds, using rel2abs to deal with relative links and a hash to check for loops. I think it could be adapted to your needs.

#!/usr/bin/perl use warnings; no warnings 'uninitialized'; use strict; use File::Spec qw(rel2abs); use File::Basename; chaselink($ARGV[0]); sub chaselink { my %seen = (); my $chase; $chase = sub { my($f,$d)=@_; print "\nChasing link '$f' in '$d'\n"; my $l = readlink($f); if (!defined($l)) { print "$f is not a link.\n"; return undef; } print "Relative link: $l from $d\n"; my $a = File::Spec->rel2abs($l,$d); print "Absolute link: $a\n"; if ($seen{$a}) { print "Found loop, giving up\n"; return undef; } $seen{$a}=1; $chase->($a,dirname($a)); }; $chase->(@_); }

Replies are listed 'Best First'.
Re^2: Following symlinks manually
by Anonymous Monk on Jul 07, 2010 at 21:57 UTC
    This fragment follows the symlinks of $0 (the program name) to determine the home directory for the current program. While it's impossible for there to be a loop (the program got started, after all), the code does check for loops.

    I'm not happy about the `pwd` dependency, but 'use Cwd' would have been longer and because I put this code in my BEGIN {} block, I wasn't sure if I could use 'use'. Also, it assumes '/' is the path separator and that \r and \n don't appear in the program pathname.

    my $linkcount=50; (my $file=$0)=~s/.*\///; (my $HOME=$0)=~s/[^\/]*$//; $HOME||=`pwd`."/"; $HOME=~s/[\r\n]//g; while (defined(my $l=readlink($HOME.$file))) { if ($linkcount--<0) {die("$0: symlink loop detected, dying\n");} ($file=$l)=~s/.*\///; if (substr($l,0,1) eq "/") {($HOME=$l)=~s/[^\/]*$//;next;} (my $npwd=$l)=~s/[^\/]*$//; $HOME.=$npwd; }; print "The home directory for this program is $HOME\n";