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

Hello, I have a three part question to ask... Using the code example below,
Can I combine the readdir() function and the (-M $logfile < 1) statement into one short command..?

Also is it possible to combine the " readdir(), (-M $logfile <1) and the (m/^[B|b].+.txt$/) into one line/command..?

If the first two questions are not possible can the code be shortened into fewer lines..?

#!d:\perl\bin\perl.exe $pth = "\\\\\\bex"; opendir(Directory, $pth) or die "Cannot Open Directory"; @cont = readdir(Directory); closedir(Directory); splice(@cont, 0, 2); # <-- remove " . & .. " foreach (@cont) { if (m/^[B|b].+.txt$/) { push(@contents,$_) } } foreach $content (@contents) { $logfile = "$pth" .'\\'. "$content"; if( -M $logfile < 1 ) { #less than 24 hours ago open(FILE, "$logfile"); # open logfile for reading print "$logfile\n"; close(FILE); } }

Replies are listed 'Best First'.
Re: how do I shorten code
by dga (Hermit) on Apr 03, 2003 at 20:17 UTC

    Well one shorter would be to use grep instead of the foreach @cont.

    my @contents = grep { /^[Bb].+.txt$/ } @cont;

    Also you probably want your RE to be:


    So that is only matches a file ending in .txt rather than the current match which would match 'Bobtxt' or 'Bob.txt'

    Also I don't see any point in opening the log files since you are only printing the name out anyway. You can remove the open and close for a big speedup. If you want to print the contents of the logfiles you might try:

    open(FILE, "<$logfile"); # specify read explicitly with < print "$logfile:\n"; print while(<FILE>); close(FILE);

    This will print the name of the file followed by its contents.

    Update: Also the [B|b] is not desired as it tries to match B or | or b and you probably just want B or b which the RE's provided will match. The | character in a grouping (not a char class) provides a way to alternate groups of characters like (abc|def)ghi which would match abcghi or defghi but not aecghi etc.

Re: how do I shorten code
by Enlil (Parson) on Apr 03, 2003 at 20:19 UTC
    First shorter does not mean clearer (nor better), but it is possible to shorten your code to something like so:
    #!d:\perl\bin\perl.exe $pth = "\\\\\\bex"; opendir(Directory, $pth) or die "Cannot Open Directory"; @contents = grep { m!^[Bb].+\.txt$! #assuming .txt ending and -M "$path\\$_" > 1 } readdir(Directory); closedir(Directory);
    A couple of other issues though. You do not need the splice as your regular expression would have eliminated it anyhow. and second I changed your regular expression because if you want to match a period in a regular expression you can do it one of two ways backwack it (i.e. \. )or in a character class (i.e. [.] ), the .txt in your regular expression would also match anything that ended with txt preceded by any character.

    update:A shorter solution for the whole thing (untested):

    #!d:\perl\bin\perl.exe my $pth = "\\\\\\bex"; opendir(Directory, $pth) or die "Cannot Open Directory"; while ( $_ = readdir(Directory) ) { if ( m!^[Bb].+\.txt$! and -M "$path\\$_" > 1 ) { open ( FILE, "$path\\$_" > 1 ) or die "$!"; while ( my $line = <FILE> ) { print $line; } close(FILE); } } closedir(Directory);


Re: how do I shorten code
by tachyon (Chancellor) on Apr 04, 2003 at 01:17 UTC

    Use grep to select the files you want using whatever tests you like linked with and. Get the list using glob

    my $dir = 'c:'; my @list = grep { m!^\Q$dir\E/B.+txt$!i and -M $_ < 1 } glob( "$dir/*" + ); print "$_\n" for @list;




      On a case-insensitive file system (Windows), you can shorten even further by specifying the pattern in the glob:
      my @list = grep { -M < 1 } glob "$dir/B*.txt";

        Theoretically, you should be able to do something similar on case sensitive systems.

        my @list = grep( -M < 1 } glob "$dir/b*.txt $dir/B*.txt";

        I say theoretically as I don't such a system to test it on, but the multiple args in a string seems to work ok. Of course if its not just the 'B' that can vary case, then enumerating all the Txt TXt TXT tXT txT TxT tXt etc. isn't going to shorten anything:)

        Examine what is said, not who speaks.
        "Efficiency is intelligent laziness." -David Dunham
        "When I'm working on a problem, I never think about beauty. I think only how to solve the problem. But when I have finished, if the solution is not beautiful, I know it is wrong." -Richard Buckminster Fuller
Re: how do I shorten code
by tachyon (Chancellor) on Apr 04, 2003 at 01:26 UTC

    PS: If you want it in one liner style this will do:

    my $dir = 'c:'; my $logfile = 'c:/log.txt'; `echo $_ >> $logfile` for grep { m!^\Q$dir\E/B.+txt$!i and -M $_ < 1 } + glob( "$dir/*" );




Re: how do I shorten code
by Anonymous Monk on Apr 04, 2003 at 12:43 UTC
    Why is it important to shorten the code? The path to mastery says a lot about this, most of it true?

    More important than shortening the code above is learning the important of including full information in error messages as described in perlstyle. Also include them on every system command - including every open. It is also good to get in the habit of strict.pm and declaring your variables.

    None of these will shorten your code. All will improve it. And that is more important.