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

Hi, I am trying to create a list (.txt file) of files under each subdirectory, for all subdirectories inside a main dir eg -
./rootdir ./rootdir/folder1 has files file1.txt, file2.txt,file3.txt..etc
another sub-folder
./rootdir/folder2 has files file1.txt, file2.txt,file3.txt..etc too
My script should create a list of files inside each subfolder, with path to all files corresponding to that subfolder like -
./rootdir/folder1/List1.txt ./rootdir/folder2/List2.txt
My code is not generating any file in the subfolders, can someone please point out the error EDITED code - Now my code is generating files in within each subdirectory, But the array (@subdirs) creates a key for the main directory (here ./rootdir) as well. How can I ignore reading this directory in array and just read the subdirectories using File::Find
use strict; use warnings; use File::Find::Rule; my $directory = './rootdir'; my @subdirs = File::Find::Rule->directory->in( $directory ); foreach my $dir (@subdirs) { #print "$dir\n"; next if ($dir eq ".."); if (-d $dir) { my $curr_dir = $dir; open (my $OUTFILE, '>>', "$curr_dir/List.txt") or die "Cant op +en '$dir.txt!' $!"; my @files = File::Find::Rule->file() ->name( '*.*' ) -> in( $d +ir); foreach $_ (@files) { print $OUTFILE "$_\n"; } close $OUTFILE; } } }

Replies are listed 'Best First'.
Re: creating a list of files under each subfolder in a main directory
by GrandFather (Saint) on Mar 17, 2016 at 20:33 UTC

    You are both doing too much work and too little, assuming I understand what you are trying to achieve.

    You don't need to open any files. You may need to recurse into sub-directories. Take a while to study the following code:

    #!/usr/bin/perl use strict; use warnings; use File::Find::Rule; parseDir ('./rootdir'); sub parseDir { my ($dir) = @_; my @subdirs = File::Find::Rule->directory()->in($dir); parseDir ($_) for grep {!/^\.\.?$/ && $_ ne $dir} @subdirs; my @files = File::Find::Rule->file()->name('*.*')->in($dir); return if !@files; my $listFileName = ""; open my $listFile, '>', "$dir/List.txt" or return; print $listFile join "\n", @files, ''; }

    The key to understanding it is that parseDir calls itself to deal with sub-directories. Having dealt with all sub-directories it then creates the list.txt file for the current directory.

    Premature optimization is the root of all job security

      You don't need that grep stuff

      #!/usr/bin/perl -- use strict; use warnings; use File::Find::Rule qw/ find rule /; use Path::Tiny qw/ path /; my @subdirs = rule( 'directory' , maxdepth => 1, )->in( 'startdir' ); for my $dir ( @subdirs ){ my $listFile = path( "$dir/List.txt" )->openw_utf8; rule( file => exec => sub { ## my( $shortname, $path, $fullname ) = @_; print $listFile "$_[2]\n"; return !!0; ## means discard filename }, )->in( $dir ); }
      Thanks a lot for the response! the issue is resolved
Re: creating a list of files under each subfolder in a main directory
by Discipulus (Canon) on Mar 17, 2016 at 20:18 UTC
    Hello, your code is very confusing: especially the nested open part. You are opening for read every file in each subdirectory and while reading them (ie for every line!) you open a file in append mode and write the content of the line to it...

    Meaningfull names for variables and a correct indentation (perltidy) help a lot reading code or maintain it after a while.

    If your usage of File::Find::Rule is correct (you grab first level or nested dirs?) you can try something like:

    # untested foreach my $dir (@subdirs) { # if you have .. you have also . next if ($dir eq "."); next if ($dir eq ".."); my @files = File::Find::Rule->file()->name('*.*')->in($dir); # compose a filename: # you probably need a path not just a name; you have not cd to + the inside directory # many module can hadle this for you, but you can deal with a +relative path too my $outputname = "./$dir/List.txt"; # open ALWAYS a lexical FH using the 3 args form.. open my $lexical_filehandle, '>', $outputname or die "Cannot w +rite to $outputname"; # print each filename to the listfile print $lexical_filehandle "$_\n" for @files; close $lexical_filehandle; }#next dir will be processed

    L*

    PS you can also play with:

    find . -type d -maxdepth 1 | perl -lne "system qq(ls $_ > ./$_/_list +.txt)"

    There are no rules, there are no thumbs..
    Reinvent the wheel, then learn The Wheel; may be one day you reinvent one of THE WHEELS.
      Thanks a lot for your reply! I realized I didnt need to read each file in subdirectory and I edited my code based on your and other suggestion. Your code and my edited code generates list file within each subdirectory, but I am facing one issue. The array (@subdirs) creates a key for the main directory (here ./rootdir) as well. How can I ignore reading this directory in array and just read the subdirectories using File::Find? Thanks a lot!
Re: creating a list of files under each subfolder in a main directory
by Laurent_R (Canon) on Mar 17, 2016 at 23:47 UTC
    A bare bone recursive exploration of a sub-directory tree:
    sub explore_dir { my ($path) = @_; my @dir_entries = glob("$path/*"); foreach my $entry (@dir_entries) { print "$path$entry\n" if -f $entry; explore_dir($entry) if -d $entry; } } explore_dir($start_path);
    (I know it would be more politically correct to use a module, but, in such a case, it is in my view pedagogically more efficient to show a way to do everything in pure core Perl.)
Re: creating a list of files under each subfolder in a main directory
by akuk (Beadle) on Mar 18, 2016 at 12:37 UTC
    Just try to use the below code
    open (my $OUTFILE, '>', "$curr_dir/List.txt") or die "Cant op +en '$dir.txt!' $!";
    for opening the file handle....