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

Dear monks,

Could you possibly enlighten me with the following issue? I have to write perl code that should delete files of a known directory whose name matches a certain pattern. Therefore, I used
opendir (DIRHANDLE, "/path/of/dir") or die "Cannot open directory $!\n +"; unlink grep (/$mypattern/i, readdir DIRHANDLE); closedir DIRHANDLE;
This works if the script is executed in the directory where the files reside, but does not work in any other directory. Is there a solution using similar syntax or I have to rewrite it in a more verbose way (e.g. creating the list of files and then with a foreach loop, unlink "${dirname}/${filename}")?

Cheers,
Athanasia

Replies are listed 'Best First'.
Re: Unlink files but not in pwd
by kyle (Abbot) on Mar 27, 2009 at 16:05 UTC

    You could use s/// to both pattern match and insert the source directory in one step.

    my $dir = '/path/of/dir'; opendir my $dh, $dir or die "Can't opendir '$dir': $!\n"; unlink grep s{^(.*$mypattern)}{$dir/$1}i, readdir $dh;

    You could get better error reporting (which would have been useful here) if you call unlink in a loop with the "do or die" idiom instead.

    # opendir as above foreach my $file ( grep /$mypattern/i, readdir $dh ) { my $path = "$dir/$file"; unlink $path or die "Can't unlink '$path': $!\n"; }
Re: Unlink files but not in pwd
by baxy77bax (Deacon) on Mar 27, 2009 at 15:55 UTC
    hi ,

    well you should define the path to the file you want to delete :)

    something like this:

    opendir (DIRHANDLE, "./dir") or die "Cannot open directory $!\n"; my @l = grep (/hh.txt/i, readdir DIRHANDLE); unlink("./dir/$l[0]"); closedir DIRHANDLE;
    the point is that when you call readdir on a dir you get an array of names of the files in that dir and not the full path to the file in dir

      Hi baxy77bax,

      Very true :-). However, this kind of implies that I cannot delete the whole list @l at once and using a foreach loop is inevitable. Anyway, don't know why I insist so much on a one-liner, I am usually quite verbose when coding.

      Thanks,
      Athanasia
        You can avoid the foreach if you use map:
        opendir(my $dh, './dir') || die "opendir: $!"; unlink map { "./dir/$_" } grep { /$mypattern/i } readdir $dh; closedir $dh;
Re: Unlink files but not in pwd
by Illuminatus (Curate) on Mar 27, 2009 at 15:52 UTC
    Why use perl (unless this is homework)?
    find "/path/of/dir" -name 'shell-type-glob-for-file' -delete
    You can also use perl-type regex's with regex and regextype options
      Hi Illuminatus,

      Thanks for your reply!

      Actually, this is a part of a bigger perl script. Of course, you are right, I could use unix's find in a system command, but that would mean shell invokation and I would prefer not to.

      Could you be more specific about your suggestion using regex options?

      Athanasia
        The options I mentioned are to find. Your initial post about having to prepend the path (also in another reply) does not seem all that odious. You could also check out File::Find
Re: Unlink files but not in pwd
by grinder (Bishop) on Mar 27, 2009 at 20:38 UTC

    With recent versions of File::Path you can do the following:

    use File::Path 'remove_path'; remove_path("/path/of/dir", {keep_root => 1});

    This will remove everything in the directory, but not delete /path/of/dir itself.

    update: oh, you want to unlink according to a pattern; I missed that on the first pass.

    • another intruder with the mooring in the heart of the Perl