Search code examples
perlfilefindrulefile-find

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.


Solution

  • 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 it 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 other ways to sort/filter/etc a 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 is meant for search and not suitable for sorting.

    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 use core File::Copy, while for temporary files core File::Temp is useful.