Reputation: 109
I have faced some issue on how to find a symlink inside a directory using Find library, it can't be found and I am very new in using Perl.
use strict;
use warnings;
use File::Find::Rule;
use File::Find;
use File::Copy;
my @files = File::Find::Rule->file()
->name( 'table.txt' )
->in( '/a/b/c' );
for my $file (@files)
{
print "\nfile: $file\n";
Supposedly there is another directory that contain the specified file, table.txt, but it is a symlink that is /a/b/d, but the symlink is not there when it is printed out.
Upvotes: 1
Views: 1050
Reputation: 66883
The File::Find::Rule implements the -X filetests, as methods. The one that tests whether an entry is a symlink (-l
) is called symlink
.
In my reading of the question you don't know the name of that directory (otherwise, why "find" a file in it?), except that it is a symbolic link. Then you need to first find directories which are symlinks, then find files in them. For this second task you'll need to tell the module to follow the links.
I use a test structure on disk
test_find/a/c/c.txt test_find/a/b/b.txt test_find/is_link -> a/c ("is_link" is a symbolic link to "a/c")
and from the directory right above it I run the program
use warnings;
use strict;
use feature 'say';
use File::Find::Rule;
my $top_dir = shift @ARGV || './test_find';
my @symlink_dirs = File::Find::Rule->directory->symlink->in($top_dir);
foreach my $dir (@symlink_dirs) {
my @files = File::Find::Rule->file->extras({follow => 1})->in($dir);
say "in $dir: @files";
}
which prints
in test_find/is_link: test_find/is_link/c.txt
Note that the program will find all files in all directories which are symlinks. Writing an explicit loop as above allows you to add code to decide which of the symlink-directories to actually search. If you don't mind looking through all of them you can just do
my @files = File::Find::Rule->file->extras({follow => 1})->in(@symlink_dirs);
See documentation for features to limit the search using what you know about the directory/file.
If the link directory is in a hierarchy not including the target, then simply search that hierarchy.
With test structure
other_hier/is_link -> ../test_find/a/c test_find/a/c/c.txt
you only need to tell it to follow the links
my @all_files = File::Find::Rule # may use linebreaks and spaces
-> file
-> extras({ follow => 1 })
-> in('other_hier');
When added to the above program and printed this adds
another/is_link/c.txt
You can of course replace the literal 'other_hier'
with $top_dir
and invoke the program with argument other_hier
(and make that other_hier
directory and the link in it).
If both link and target are in the same hierarchy that is searched then you can't do this; the search would run into circular links (the module detects that and exits with error).
Upvotes: 2