Ria Ria - 29 days ago 15
Perl Question

Perl: How to use File::Find::Rule to list all symbolic links from a given path

ls /foo/bar/

lrwxr-xr-x a1 -> ../../../a1
lrwxr-xr-x a2 -> ../../../a2
lrwxr-xr-x a3 -> ../../../a3


This is a curtailed output of ls.

My goal:
1. Go to /foo/bar/ and find the latest version of a (which is a symbolic link). So in this case, a3. Copy the contents of a3 to a temp location

I am trying to use
File::Find::Rule
but I am unable to figure out how to use it to list all the symbolic links. Reading through various Google sites, I see people explaining how to follow the symbolic links but not to list them.

What I have figured out so far:

my $filePath = "/foo/bar";
my @files = File::Find::Rule->file->in(filePath);


This returns an empty array because there there are no files only symbolic links in /foo/bar.
I also tried
my @files = File::Find::Rule->in($makeFilePath)->extras({follow =>1});

but I feel that is asks to follow the symbolic link rather than list them.

Answer

Use the symlink method from -X test synonyms provided in File::Find::Rule

use warnings 'all';
use strict;

use File::Find::Rule;

my $rule = File::Find::Rule->new;

my @links = $rule->symlink->in('.');

print "@links\n";

This finds all files which satisfy -l file test in the current directory. Also see -X.

With the list of links on hand, you can use the -M file test or stat (or its File::stat by-name interface), to sort out by timestamps of the target files. For example

use List::Util 'max';
my %ts_name = map { (stat)[9] => $_ } @links;
my $latest = $ts_name{ max (keys %ts_name) };

There are many other ways to sort/filter/etc the list. If you use -M then you need min. If you wanted the timestamps for the link itself for some reason, use the lstat instead. The module also provides an mtime method for work with timestamps, but it isn't very suitable for sorting things.

Note that you don't have to actually create an object first, but can directly do

use File::Find::Rule;
my @links = File::Find::Rule->symlink->in('.');

To copy/move things around use File::Copy.