Beefy Boxes and Bandwidth Generously Provided by pair Networks
Welcome to the Monastery
 
PerlMonks  

Re^2: Recursively walk up a directory tree

by 1nickt (Canon)
on Feb 10, 2018 at 19:37 UTC ( [id://1208919]=note: print w/replies, xml ) Need Help??


in reply to Re: Recursively walk up a directory tree
in thread Recursively walk up a directory tree

Thanks for the suggestion! I see the (??{ ... }) code-as-match, but can't see where it recurses or loops. Could you please explain?


The way forward always starts with a minimal test.

Replies are listed 'Best First'.
Re^3: Recursively walk up a directory tree
by tybalt89 (Monsignor) on Feb 10, 2018 at 22:21 UTC

    The looping is done by the regex engine, trying to find the longest match, and if it fails, the next longest, etc.

    Try adding a print statement inside the code block and you can see each directory before the test for .marker.

    Like so:

    cwd =~ m#^(.*)(?:/|$)(??{print "testing $1\n"; ! -f "$1/.marker"})# or + die " .marker not found";
Re^3: Recursively walk up a directory tree
by AnomalousMonk (Archbishop) on Feb 10, 2018 at 22:29 UTC

    The  cwd() function gives the full path of the... well, CWD. The match looks for a file at the end (rightmost part) of the path. If the file is not found, the regex engine effectively backtracks up a level in the directory.

    The  ! -f "$1/.marker" code in the  (??{ CODE }) construct evaluates to  '' (empty string) if the file exists at a given level, and this is interpolated into the regex pattern and always matches, hence the file is "found" at that level.

    If the file is not found, the negated file test evaluates to  '1' and this will probably not be found at the beginning of a directory name. However, this can fail (debug print added to show progress):

    use strict; use warnings; use Cwd; my $marker = '.marker'; cwd =~ m#^(.*)(?:/|$)(??{ print "at level '$1' \n"; ! -f "$1/$marker" +})# or die "'$marker' not found"; print "found '$marker' in '$1' \n";
    Output (with no  .marker file present anywhere):
    c:\@Work\Perl\monks\1nickt\two\one\zero>perl find_marker_1.pl at level 'c:/@Work/Perl/monks/1nickt/two/one/zero' at level 'c:/@Work/Perl/monks/1nickt/two/one' at level 'c:/@Work/Perl/monks/1nickt/two' at level 'c:/@Work/Perl/monks/1nickt' at level 'c:/@Work/Perl/monks' found '.marker' in 'c:/@Work/Perl/monks'
    If you have Perl version 5.10+, there's a variation that avoids this problem:
    use 5.010; # needs (?(?{ CODE })yes-pattern) regex extension use strict; use warnings; use Cwd; my $marker = '.marker'; cwd =~ m{ \A (.*) (?: / | \z) # (??{ print "at level '$1' \n"; ! -f "$1/$marker"}) (?(?{ print "at level '$1' \n"; ! -f "$1/$marker" }) (*FAIL)) }xms or die "'$marker' not found"; print "found '$marker' in '$1' \n";
    Output (still no  .marker file):
    c:\@Work\Perl\monks\1nickt\two\one\zero>perl find_marker_2.pl at level 'c:/@Work/Perl/monks/1nickt/two/one/zero' at level 'c:/@Work/Perl/monks/1nickt/two/one' at level 'c:/@Work/Perl/monks/1nickt/two' at level 'c:/@Work/Perl/monks/1nickt' at level 'c:/@Work/Perl/monks' at level 'c:/@Work/Perl' at level 'c:/@Work' at level 'c:' '.marker' not found at find_marker_2.pl line 62.
    Both versions of code behave the same if a  .marker is present at some level, although the first version will fail if the  .marker file is present above the level of, say, the  1nickt directory.


    Give a man a fish:  <%-{-{-{-<

Log In?
Username:
Password:

What's my password?
Create A New User
Domain Nodelet?
Node Status?
node history
Node Type: note [id://1208919]
help
Chatterbox?
and the web crawler heard nothing...

How do I use this?Last hourOther CB clients
Other Users?
Others pondering the Monastery: (4)
As of 2024-04-23 22:57 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    No recent polls found