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



If pathlist is given as @ARGV[0], how to get all the files present in that pathlist. For example: 1) C:\ - All Files in the root directory 2) C:\* - All files on entire volume. 3) C:\directoryname\ - All files in directoryname. 4) C:\directoryname\* - All files in directoryname and its subdirectories.

I got the following tool from user = blazar to get the files for the mentioned directory  perl -MFile::Find -le "find { no_chdir =>1, wanted => sub {print} }, @ARGV" C:\temp\ but it gives everything in that directory as well as in subdirectories. Is there any way to mention depth ? What I mean is, if I give c:\temp, it should only show me the directories and files in that directory and not under the its subdirectories.  perl -MFile::Find -le "find { no_chdir =>1, wanted => sub {print} }, @ARGV" C:\temp\
Thanks.

Replies are listed 'Best First'.
Re: To retrieve all files according to given path list
by Joost (Canon) on Dec 22, 2005 at 16:21 UTC
Re: To retrieve all files according to given path list
by blue_cowdawg (Monsignor) on Dec 22, 2005 at 16:28 UTC
        how to get all the files present in that pathlist.

    What have you tried and failed at? Let's see some code please!

    There is more ways of doing what you are asking than there are programmers programming in Perl. One suggestion I would give you is to run the "find2perl" command with a minimum of arguments to produce a file you can hack on.

    For instance if I run the command

    find2perl somedir -depth -type f > somefile.pl
    I will get the starts of a program in the file somefile.pl with the following contents:
    #! /usr/bin/perl -w eval 'exec /usr/bin/perl -S $0 ${1+"$@"}' if 0; #$running_under_some_shell use strict; use File::Find (); # Set the variable $File::Find::dont_use_nlink if you're using AFS, # since AFS cheats. # for the convenience of &wanted calls, including -eval statements: use vars qw/*name *dir *prune/; *name = *File::Find::name; *dir = *File::Find::dir; *prune = *File::Find::prune; sub wanted; # Traverse desired filesystems File::Find::finddepth({wanted => \&wanted}, 'somedir'); exit; sub wanted { my ($dev,$ino,$mode,$nlink,$uid,$gid); (($dev,$ino,$mode,$nlink,$uid,$gid) = lstat($_)) && -f _; }
    Now an enterprising programmer can edit that file to give it any behaviors that they want, and to boot it is a good way to learn how to use the File::Find module and friends.

    Now, if you wanted to re-invent the wheel you could also write something that was a combination of calls to opendir and friends with some glob calls to handle wildcards and things like that.

    I hope this nudges you on to the path of Perl Rightousness...


    Peter L. Berghold -- Unix Professional
    Peter -at- Berghold -dot- Net; AOL IM redcowdawg Yahoo IM: blue_cowdawg


      I have tried following code, where I am assigning @ARGV[0] to $directory variable and then passing $directory variable to sub wanted as you can see in the following code. But it only accepts "C:\directoryname" as an argument. I want the code to handle all the cases such as "C:\", "C:\*", C:\direcoryname\*" etc as I showed in my original email. Also is there any way to handle multiple paths or pathlist provided on command line ?

      Please help.

      Thanks
      find(\&wanted, $directory); sub wanted { if (-d $_) { $totaldirs++; return; } else { $totalfiles++; @Stats = stat($_); $size = $Stats[7]; $ATime = $Stats[8]; $ModTime = $Stats[9]; $CTime = $Stats[10]; if (!$Windows && $opt_o ) { $owner = $Stats[4]; $owner = "\\" . getpwuid($owner); if ($owner eq "\\") { $owner = ''; } } elsif ($hasWin32Perms && $opt_o) { $object = new Win32::Perms ( $_ ) || die; $owner = $object->Owner(); $object->Close(); } ################################################################## +################ ## Filter Checks # Owner if ($i_owners && ($i_owners ne $owner) && $opt_o) { return; } # File Size if ($i_filesizemax && $i_filesizemin) { if ($size > $i_filesizemax || $size < $i_filesizemin) { next; +} } # Included File Types if (@i_incfiletypes) { $match = 0; foreach my $ext (@i_incfiletypes) { $ext =~ s/^\.//; if ($_ =~ m/.$ext$/) { $match = 1; last; } } if (!$match) { return; } } # Excluded File Types if (@i_excfiletypes) { $match = 0; foreach my $ext (@i_excfiletypes) { $ext =~ s/^\.//; if ($_ =~ m/.$ext$/) { $match = 1; last; } } if ($match) { return; } } # Date Modified if ($i_datemodifiedstart && $i_datemodifiedend) { if ($ModTime < $i_datemodifiedstart || $ModTime > $i_datemodif +iedend) { next; } } # Date Created if ($i_datecreatedstart && $i_datecreatedend) { if ($CTime < $i_datecreatedstart || $CTime > $i_datecreatedend +) { next; } } # Date Accessed if ($i_dateaccessedstart && $i_dateaccessedend) { if ($ATime < $i_dateaccessedstart || $ATime > $i_dateaccessede +nd) { next; } } $filterfiles++; ################################################################## +################ $writer->startTag("File"); ## OWNER ### $writer->dataElement("FileOwner", $owner);All files in directoryna +me and its subdirectories. $dir = $File::Find::dir; #$dir =~ s!\/!!; $dir =~ s!/!\\!g; $dir =~ s!\\\\!\\!; $dir = $dir . "\\"; $dir =~ s!:\\\\!:\\!; $writer->dataElement("FilePath", $dir); $writer->dataElement("FileName", $_); ################################################################## +################ ## FILE ACCESSED ($sec,$min,$hour,$mday,$mon,$year,$wday,$yday,$isdst) = localtime( +$ATime); $year += 1900; $mon++; $mday = "0$mday" if $mday < 10; if ($hour > 12) { $hour = $hour - 12; $ampm = "PM"; } else { $hour = 12 if $hour == 0; $ampm ="AM"; } $min = "0$min" if $min < 10; $sec = "0$sec" if $sec < 10; #print "\t\t<FileAccessed>$mon/$mday/$year $hour:$min:$sec $ampm< +/FileAccessed>\n"; #$writer->dataElement("FileAccessed", "$mon/$mday/$year $hour:$min +:$sec $ampm"); $writer->dataElement("FileAccessed", "$mon/$mday/$year"); ################################################################## +################ ## FILE MODIFIED ($sec,$min,$hour,$mday,$mon,$year,$wday,$yday,$isdst) = localtime( +$ModTime); $year += 1900; $mon++; $mday = "0$mday" if $mday < 10; if ($hour > 12) { $hour = $hour - 12; $ampm = "PM"; } else { $hour = 12 if $hour == 0; $ampm ="AM"; } $min = "0$min" if $min < 10; $sec = "0$sec" if $sec < 10; #print FH "\t\t<FileModified>$mon/$mday/$year $hour:$min:$sec $amp +m</FileModified>\n"; #$writer->dataElement("FileModified", "$mon/$mday/$year $hour:$min +:$sec $ampm"); $writer->dataElement("FileModified", "$mon/$mday/$year"); ################################################################## +################ ## FILE CREATED ($sec,$min,$hour,$mday,$mon,$year,$wday,$yday,$isdst) = localtime( +$CTime); $year += 1900; $mon++; $mday = "0$mday" if $mday < 10; if ($hour > 12) { $hour = $hour - 12; $ampm = "PM"; } else { $hour = 12 if $hour == 0; $ampm ="AM"; } $min = "0$min" if $min < 10; $sec = "0$sec" if $sec < 10; #$writer->dataElement("FileCreated", "$mon/$mday/$year $hour:$min: +$sec $ampm"); $writer->dataElement("FileCreated", "$mon/$mday/$year"); ################################################################## +################ # Turn size into KB and round up to next integer divisible by 4 $size = ceil($size / 1024); while ($size % 4 != 0) { $size++; } $writer->dataElement("FileSize", $size); $writer->endTag(); } } $writer->endTag(); $writer->end(); $output->close(); ##################################################################### print "File Scan is complete.\n"; print ":::Statistics:::\nDirectories:\t$totaldirs\nFiles:\t$totalfiles +\nFiles that passed Filters:\t$filterfiles\n";
            I want the code to handle all the cases such as "C:\", "C:\*", C:\direcoryname\*" etc as I showed in my original email.

        For that you are going to have to write logic to expand out your wild cards. For instance take a look at glob. There are other ways, but that's a start.


        Peter L. Berghold -- Unix Professional
        Peter -at- Berghold -dot- Net; AOL IM redcowdawg Yahoo IM: blue_cowdawg
        I have tried following code, where I am assigning @ARGV[0] to $directory variable and then passing $directory variable to sub wanted as you can see in the following code. But it only accepts "C:\directoryname" as an argument. I want the code to handle all the cases such as "C:\", "C:\*", C:\direcoryname\*" etc as I showed in my original email. Also is there any way to handle multiple paths or pathlist provided on command line ?

        When I'm under windows I often do

        BEGIN { @ARGV = map glob, @ARGV }

        And indeed to File::Find's find() you can pass more than one directory to search. From perldoc File::Find:

        SYNOPSIS use File::Find; find(\&wanted, @directories_to_search); sub wanted { ... } use File::Find; finddepth(\&wanted, @directories_to_search); sub wanted { ... }
Re: To retrieve all files according to given path list
by blazar (Canon) on Dec 22, 2005 at 16:18 UTC

    Asked quite often! Usual -good- answer: use File::Find or its relatives, File::Finder and File::Find::Rule.

    perl -MFile::Find -le "find { no_chdir =>1, wanted => sub {print} }, @ +ARGV" C:\temp\

    (should work under Windows with double quotes)

    Incidentally @ARGV[0] is not strictly wrong, but in Perl 5 it is more customary to write $ARGV[0] instead.

      Not quite. While it's a step in the right direction, your program dies on inputs (2) and (4), and returns the incorrect result for inputs (1) and (3). The OP's tool has a very odd usage syntax.

      devlele, have you considered using a switch (say -r) to decide whether to recurse or not. * normally means something else.

        Not quite. While it's a step in the right direction, your program dies on inputs (2) and (4), and returns the incorrect result for inputs (1) and (3). The OP's tool has a very odd usage syntax.
        Oh, that was just for illustrational purposes. Of course it would be up to him to decide to which depth level to recurse based upon actual input. Indeed the requirements are quite strange...
Re: To retrieve all files according to given path list
by marto (Cardinal) on Dec 22, 2005 at 16:19 UTC
    Hi devele,

    What have you tried so far?
    Have you used Super Search to look for this?
    Have you looked at the File::Find module?

    Hope this helps

    Martin