Question

I'm currently writing a Perl program that is to read a given file (either command-line or hard-coded) and then recursively print (and open if extension is .bragi) files and directories listed. For example:

~
    hello.bragi
    subdir/
~/subdir
    check.bragi

where

master.bragi:

~/hello.bragi

and

hello.bragi:

subdir/

and

check.bragi:

main.c

The program would open master.bragi, see hello.bragi listed, open it to find a directory listed, open that directory, then repeat.

I currently have this code:

#!/usr/bin/perl -w

use strict;
use File::Basename;

sub isdir {
    return (-d $_[0]);
}

sub isfile {
    return (-f $_[0]);
}

sub getfn {
    my $path = $_[1];
    my (undef, undef, my $ext) = fileparse($_[0], qr"\..*");
    print "arg:\t".$path."\n";
    if ($ext eq ".bragi") {
    open FILE, "<", $path.$_[0] or die $!;
    my @lines = <FILE>;
    foreach my $line (@lines) {
        chomp($line);
        if (isfile($line)) {
        print "file:\t".$path.$line."\n";
        }
        if (isdir($line)) {
        print "DIR:\t".$line."\n";
        opendir my ($dh), $path.$line or die "Filename does not exist: $!";
        my @files = readdir $dh;
        closedir $dh;
        #print $files[0].":\t".$path.$line."/\n";
        foreach my $f (@files) {
            my $next = $path.$line."/";
            getfn($f, $next);
        }
        }
    }
    }
}

getfn("master.bragi", "/home/tekknolagi/twentytwelve/fs/");

Except I get some errors like No such file or directory at ./files.pl line 19, <FILE> line 3.

And I'm not entirely sure what I'm doing. Thoughts?

Expected output (in order):

master.bragi
hello.bragi
check.bragi
main.c
Was it helpful?

Solution

One problem is that you're not using the core module File::Find. This is designed to make directory traversals easier.

Another problem is that you have use strict; commented out.

Another problem is that you don't create my variables for the parameters to getfn(). At the very least that is aconventional; using good variable names makes it much easier to understand the code.

I take back the previous comment about File::Find. Here's a hacked version of your script that seems to work:

#!/usr/bin/perl -w

use strict;
use File::Basename;
use constant debug => 0;

sub isdir {
    return (-d $_[0]);
}

sub isfile {
    return (-f $_[0]);
}

my $level = 0;

sub getfn {
    my($file, $path) = @_;
    my (undef, undef, $ext) = fileparse($file, qr"\.[^.]+$");
    $level++;
    print "-->>getfn($level): $file : $path\n" if debug;
    print "arg:\t$file\t$path ($ext)\n" if debug;
    if ($ext eq ".bragi") {
        open my $FILE, "<", "$path/$file" or die "Failed to open $path/$file: $!";
        my @lines = <$FILE>;
        close $FILE;
        foreach my $line (@lines) {
            chomp($line);
            my $fullpath = "$path/$line";
            print "---- $fullpath\n" if debug;
            if (isfile($fullpath)) {
                print "file:\t$fullpath\n";
                getfn($line, $path);
            }
            elsif (isdir($fullpath)) {
                print "DIR:\t$fullpath\n";
                opendir my ($dh), $fullpath or
                    die "$fullpath does not exist or is not a directory: $!";
                my @files = readdir $dh;
                closedir $dh;
                foreach my $f (@files) {
                    getfn($f, "$fullpath");
                }
            }
        }
    }
    print "<<--getfn($level)\n" if debug;
    $level--;
}

getfn("master.bragi", $ENV{PWD});

I created a test environment in the current directory like this:

mkdir subdir
echo hello.bragi > master.bragi
echo subdir > hello.bragi
echo main.c > subdir/check.bragi
echo hello > subdir/main.c

The output of the command is:

file:   /Users/jleffler/tmp/soq/hello.bragi
DIR:    /Users/jleffler/tmp/soq/subdir
file:   /Users/jleffler/tmp/soq/subdir/main.c
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top