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

I wrote a simple that prints only files recursively. But I have a problem.
whenever It meets named pipe, it gets blocked at all!
I thought it would be ok if I add just -p test,but that's too late because program is blocked when opening the named pipe!

#!/usr/bin/perl -w use latest; use File::Spec; my $test=$ARGV[0]; my $ds='/'; sub bfs { my $path=$_[0]; push(my @queue,$path); my ($current,@output); while(@queue) { $path=shift(@queue); if($path=~/${ds}\.{1,2}$/){next} opendir($current,$path) or open($current,$path) or next; if(-d $current) { push @queue,map {File::Spec->catfile($path,$_)} readdir $c +urrent; closedir $current } elsif(-f $current) { say $path; close $current; push @output,$path; } } @output; } bfs($test);

Replies are listed 'Best First'.
Re: Whenever perl meets namedpipe it gets blocked
by kennethk (Abbot) on Jan 23, 2015 at 19:00 UTC
    Why are you relying on open to determine your type? -f works just fine on expressions, a.k.a. paths in strings.
    #!/usr/bin/perl -w use latest; use File::Spec; my $test=$ARGV[0]; sub bfs { my $path=$_[0]; push(my @queue,$path); my @output; while(@queue) { $path=shift(@queue); if (-d $path) { my $dirname = (File::Spec->splitdir($path))[-1]; # Grab th +e last entry next if $dirname =~ /^\.\.?$/; # . or .. opendir my $dh,$path or die "opendir failure, $path: $!"; push @queue,map {File::Spec->catfile($path,$_)} readdir $d +h; } elsif (-f $path) { say $path; } else { # say "Other entity encountered: $path"; next } } return @output; } bfs($test);
    Note I've removed the open on the files entirely, and scoped the directory handle appropriately so that Perl closes it as the variable goes out of scope. I've also used File::Spec's splitdir method to make the directory name check actually cross-platform (as long as you'd started down that path...).

    #11929 First ask yourself `How would I do this without a computer?' Then have the computer do it the same way.

Re: Whenever perl meets namedpipe it gets blocked
by Anonymous Monk on Jan 23, 2015 at 19:47 UTC

    Recursing through directories and subdirectories and doing something with every item found can be achieved by several different modules in much less code, such as Path::Class::Dir's recurse, or find from File::Find; the latter is a core module if you prefer that. There's also File::Find::Rule or Path::Tiny and a few others.

Re: Whenever perl meets namedpipe it gets blocked
by pme (Monsignor) on Jan 24, 2015 at 16:19 UTC
    Hi,

    You can do this using either BFS or DFS. Recursive method call is a great way to solve this kind of problems.

    #!/usr/bin/perl -w use strict; sub bfs { my $dir = shift; return unless defined $dir; opendir(my $dh, $dir) || die; while (readdir $dh) { next if /^\.{1,2}$/; $_ = "$dir/$_"; if (-d) { push @_, $_; ### } elsif (-f) { print "$_\n"; } else { print "Something else: $_\n"; } } closedir $dh; bfs(@_); } sub dfs { my $dir = shift; return unless defined $dir; opendir(my $dh, $dir) || die; while (readdir $dh) { next if /^\.{1,2}$/; $_ = "$dir/$_"; if (-d) { unshift @_, $_; ### } elsif (-f) { print "$_\n"; } else { print "Something else: $_\n"; } } closedir $dh; dfs(@_); } print "=== BFS ===\n"; bfs(@ARGV); print "=== DFS ===\n"; dfs(@ARGV);