Re: Detecting if a folder is a symbolic link
by friedo (Prior) on Mar 17, 2006 at 22:49 UTC
|
if( -l $file ) {
# file is a symlink
}
| [reply] [d/l] |
Re: Detecting if a folder is a symbolic link
by merlyn (Sage) on Mar 17, 2006 at 23:16 UTC
|
To avoid duplicates, you can sidestep the symlink issue (because any given file might also be a symlink) by stat'ing everything you process and rejecting anything where the dev/inode pair is the same. In other words:
BEGIN {
my %seen;
sub process {
my $entry = shift;
my ($dev, $ino) = stat $entry or return;
$seen{"$dev $ino"}++ or return;
... rest of processing ...
}
}
| [reply] [d/l] |
Re: Detecting if a folder is a symbolic link
by Tanktalus (Canon) on Mar 17, 2006 at 23:04 UTC
|
friedo points out -l. I'll add two more pieces: using lstat (which is what -l uses i under the covers), which gets way too complicated, and using readlink to read the symlink.
Note that while you can use the "_" special variable for the -X operators, you need to be careful when you're involving the -l. You can't do if (-d $file && -l _). That will always return false. You must reverse that: if (-l $file && -d _). The reason is that the -d check (and everything except -l) will use stat which follows symlinks reading the underlying file, directory, device, FIFO, whatever. That will never be a symlink (unless it points to a nonexistant entity). Of course, if it points to a nonexistant entity, it won't be a directory ;->
if (-d $file && -l $file) should work fine, albeit the tiniest bit more expensive than if (-l $file && -d _).
Also be careful with readlink. It can be awfully tricky to follow symlinks the way that the OS does. Symlinks to symlinks to files inside symlink'd directories ... it's really convoluted. You're probably better off using stat (not lstat) and using the first two fields (dev and ino) as hash keys to keep track of whether you've seen it or not. This will actually also catch hardlinked files which you probably aren't even thinking about ;-)
{
my %seen;
sub have_seen_file {
my $file = shift;
my ($dev, $ino) = stat($file);
$seen{$dev}{$ino}++;
}
sub reset_seen_files { %seen = () }
}
Or something like that.
Update: tye is right - I normally actually use this shortcut as "if (-l $file || -d _)" which, of course, is not what the OP wanted. | [reply] [d/l] [select] |
|
You can't do if (-d $file && -l _). That will always return false.
True.
You must reverse that: if (-l $file && -d _).
Actually, that also always returns a false value. The cached lstat results did not follow the symbolic link and so doesn't know anything about what (if anything) it links to. If you want to check for "X is a (symbolic) link to a directory", then you can't avoid doing [l]stat twice (well, lstat once and stat once).
There certainly are cases where you can "cheat" (or "be efficient"). Perhaps you were thinking of a very common case, for example:
if( ! -l $file && -d _ ) {
}
#or
if( -l $file ) {
...
} elsif( -d _ ) {
...
} elsif( -f _ ) {
...
} else {
...
}
That does work and does require that you do the -l part first.
| [reply] [d/l] [select] |
|
What does "_" mean here? ( Referring to -d _ )
| [reply] |
|
| [reply] |
Re: Detecting if a folder is a symbolic link
by borodache (Novice) on Mar 28, 2018 at 13:02 UTC
|
Hi All,
I am doing a bit of a different script, but I need the same functionality. I need to distinguish between files, folders and links. I am using:
if (-l $file), if (-d $file) and if (-f $file).
However, it doesn't work. Files are indeed classified as files (I don't know about link to files cause I don't have them), but links (to directories) are classified as directories and not links. I dag the whole web and found that -l works only on links appropriates to the OS. However, even when I created on Windows link using mklink, it was classified as a directory. Does somebody has any idea? | [reply] |
|
If you look at the documentation for the -X functions, the -l test is described as:
File is a symbolic link (false if symlinks aren't supported by the file system).
If you look at the Alphabetical Listing of Perl Functions section of perlport, the following note is listed under -X:
(Win32, VMS, RISC OS) -g , -k , -l , -u , -A are not particularly meaningful.
Based on those documents, it looks like -l is not going to work on Windows.
I'm not saying this is the best alternative, but one alternative that you could consider is the testL function from the Win32::LongPath module.
| [reply] |
|
Hi,
I am doing this script in my workplace, and we are not allowed to add any external (cpan) library. Is there another solution?
| [reply] |
|
|
Re: Detecting if a folder is a symbolic link
by ralphch (Sexton) on Mar 19, 2006 at 14:33 UTC
|
Hi, thanks for all of your replies! I used if(!-l $file && -d $file) and it's working great.
Regards,
Ralph
| [reply] [d/l] |
Re: Detecting if a folder is a symbolic link
by borodache (Novice) on Mar 28, 2018 at 13:53 UTC
|
https://perldoc.perl.org/functions/-X.html
"-l File is a symbolic link (false if symlinks aren't supported by the file system)" - Does it mean -l doesn't work on Windows? | [reply] |