Beefy Boxes and Bandwidth Generously Provided by pair Networks
There's more than one way to do things
 
PerlMonks  

File::Find and remove invalid symlinks question

by redtux (Sexton)
on Jul 21, 2020 at 11:48 UTC ( #11119590=perlquestion: print w/replies, xml ) Need Help??

redtux has asked for the wisdom of the Perl Monks concerning the following question:

Hi

I have two approaches to getting a list of invalid symlinks (using File::Find). Both of which appear to give the same results.

Is anyone aware of any gotchas between the two

1. Using dangling_symlinks

my %findopts=(wanted=>sub{},follow => 1, dangling_symlinks => sub { my ($link,$dir)=@_; if (-l $link){ $dangle{$dir.$link}=$dir;#$File::Find::name } } ,follow_skip => 2 ); find(\%findopts, @{$dirs} );

2. using -l && !-e

find( {wanted=> sub{if (-l && !-e){ my $dir=$File::Find::dir; $dir=~s/\\/\\\\/gxsm; push @dangle,$File::Find::name; } return 1 },follow=>0}, @{$dirs} );

thanks

Mike

Replies are listed 'Best First'.
Re: File::Find and remove invalid symlinks question
by haukex (Bishop) on Jul 21, 2020 at 20:57 UTC
Re: File::Find and remove invalid symlinks question
by Eily (Monsignor) on Jul 21, 2020 at 15:53 UTC

    They give different results when I test them on a debian with perl v5.28. I have link2 -> link1 and link1 -> my_file (where my_file doesn't exist). The first version only returns link1, while the second also includes link2.

    With a dangling link "a link whose target does not exist", whether the first result is expected depends on your definition of "exist" :)

      From File::Find:
      * dangling_symlinks
      Specifies what to do with symbolic links whose target doesn't exist. If true and a code reference,
      will be called with the symbolic link name and the directory it lives in as arguments. Otherwise,
      if true and warnings are on, a warning of the form "symbolic_link_name is a dangling symbolic link\n"
      will be issued. If false, the dangling symbolic link will be silently ignored.
      

      And stat/lstat (WP):

      The stat() and lstat() functions take a filename argument. If the file is a symbolic link,
      stat() returns attributes of the eventual target of the link, while lstat() returns attributes
      of the link itself. The fstat() function takes a file descriptor argument instead, and returns
      attributes of the file that it identifies.
      
      Note: Perl docs - stat, lstat

      It seems that the question that needs to be answered is, is dangling_symlinks invoked for conditions equivalent to -l && !-e on the file is true?

      From what I dug up while getting the above clarifications, it seems that there are great pains in both documents (and elsewhere) that differentiate the link itself and the file that is the target of the link. So make sure you're being consistent in what you're testing and that you are recreating the identical conditions for which dangling_symlinks is invoked.

      Another thought occurred to me that there could be some interactions in

      sub{if (-l && !-e){

      Since you're testing $_ (I assume) when you might want (or not) to do something like sub{if (-l && !-e _){, which is going to avoid calling stat or lstat again. Not super solid on this nuance, but just saying to verify it's doing what you expect.

      Update (from From -X):

      If any of the file tests (or either the stat or lstat operator) is given the special filehandle consisting of
      a solitary underline, then the stat structure of the previous file test (or stat operator) is used, saving a
      system call. (This doesn't work with -t , and you need to remember that lstat and -l leave values in the stat
      structure for the symbolic link, not the real file.) (Also, if the stat buffer was filled by an lstat call,
      -T and -B will reset it with the results of stat _ ).
      

      So there you go...hopefully clear as mud now. :)

        Thanks for all the replies

        I think the difference between 1 and 2 is the behaviour when the link target is itself a symlink, for my use case this doesn't matter, because there will not be any links to links

        Adding _ to if (-l && !-e) makes the script return zero records. I belive this is because File::Find already does this, so it is in essence (-l $_ && !-e __)

Log In?
Username:
Password:

What's my password?
Create A New User
Domain Nodelet?
Node Status?
node history
Node Type: perlquestion [id://11119590]
Approved by LanX
Front-paged by Corion
help
Chatterbox?
and the web crawler heard nothing...

How do I use this? | Other CB clients
Other Users?
Others scrutinizing the Monastery: (3)
As of 2021-10-28 09:05 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?
    My first memorable Perl project was:







    Results (96 votes). Check out past polls.

    Notices?