4

特定のフォルダの下にあるすべてのコンテンツ(ファイルとフォルダ)を削除する必要があります。問題は、フォルダ内に何百万ものファイルとフォルダがあることです。したがって、すべてのファイル名を一度にロードしたくありません

ロジックは次のようになります。

  • すべてをロードせずにフォルダを繰り返す
  • ファイルまたはフォルダを取得する
  • それを削除し ます(ファイルまたはフォルダ「X」が削除されたことを意味します)
  • 次のものに行きます

私はこのようなことを試みています:

sub main(){
  my ($rc, $help, $debug, $root)   = ();
  $rc = GetOptions ( "HELP"           => \$help,
                     "DEBUG"          => \$debug,
                     "ROOT=s"         => \$root);

  die "Bad command line options\n$usage\n" unless ($rc);
  if ($help) { print $usage; exit (0); }

  if ($debug) {
      warn "\nProceeding to execution with following parameters: \n";
      warn "===============================================================\n";
      warn "ROOT = $root\n";

  } # write debug information to STDERR

  print "\n Starting to delete...\n";  

  die "usage: $0 dir ..\n" unless $root;
  *name = *File::Find::name;
  find \&verbose, @ARGV;

}

sub verbose {
    if (!-l && -d _) {
        print "rmdir $name\n";
    } else {
        print "unlink $name\n";
    }
}

main();

正常に動作していますが、「find」が巨大なフォルダを読み取るたびに、アプリケーションがスタックし、Perlのシステムメモリがタイムアウトまで増加しているのを確認できます。なんで?すべてのファイルを一度にロードしようとしていますか?

ご協力いただきありがとうございます。

4

7 に答える 7

7

File :: Pathremove_tree関数は、必要に応じて、最上位のディレクトリを保持したまま、ディレクトリ階層を移植可能かつ詳細に削除できます。

use strict;
use warnings;
use File::Path qw(remove_tree);

my $dir = '/tmp/dir';
remove_tree($dir, {verbose => 1, keep_root => 1});

5.10より前では、File::Pathrmtreeの関数を使用します。それでもトップディレクトリが必要な場合は、もう一度mkdirすることができます。

use File::Path;

my $dir = '/tmp/dir';
rmtree($dir, 1);  # 1 means verbose
mkdir $dir;
于 2010-04-02T17:38:52.077 に答える
6

どうしたの:

`rm -rf $folder`; // ??
于 2010-04-02T16:59:39.553 に答える
6

perlfaqは、ディレクトリをトラバースするという大変な作業を行うと指摘してFile::Findいますが、その作業はそれほど難しくありません(ディレクトリツリーに名前付きパイプやブロックデバイスなどがない場合)。

sub traverse_directory {
    my $dir = shift;
    opendir my $dh, $dir;
    while (my $file = readdir($dh)) {
        next if $file eq "." || $file eq "..";
        if (-d "$dir/$file") {
            &traverse_directory("$dir/$file");
        } elsif (-f "$dir/$file") {
            # $dir/$file is a regular file
            # Do something with it, for example:
            print "Removing $dir/$file\n";
            unlink "$dir/$file" or warn "unlink $dir/$file failed: $!\n";
        } else {
            warn "$dir/$file is not a directory or regular file. Ignoring ...\n";
        }
    }
    closedir $dh;
    # $dir might be empty at this point. If you want to delete it:
    if (rmdir $dir) {
        print "Removed $dir/\n";
    } else {
        warn "rmdir $dir failed: $!\n";
    }
}

ファイルまたは(場合によっては)空のディレクトリで何かを行うために独自のコードを使用し、処理するツリーのルートでこの関数を1回呼び出します。opendir/closedir、、、readdirの意味を-d調べ-fてください。以前にそれらに遭遇したことがない場合は。

于 2010-04-02T19:15:34.777 に答える
4

File::Findディレクトリを体系的にトラバースし、その下のファイルとディレクトリを削除するために使用できます。

于 2010-04-02T17:01:07.387 に答える
2

OK、私はPerlビルトインを譲り渡して使用しましたが、私が完全に忘れていたFile :: Path::rmtreeを使用する必要があります。

#!/usr/bin/perl

use strict; use warnings;
use Cwd;
use File::Find;

my ($clean) = @ARGV;
die "specify directory to clean\n" unless defined $clean;

my $current_dir = getcwd;
chdir $clean
    or die "Cannot chdir to '$clean': $!\n";

finddepth(\&wanted => '.');

chdir $current_dir
    or die "Cannot chdir back to '$current_dir':$!\n";

sub wanted {
    return if /^[.][.]?\z/;
    warn "$File::Find::name\n";
    if ( -f ) {
        unlink or die "Cannot delete '$File::Find::name': $!\n";
    }
    elsif ( -d _ ) {
        rmdir or die "Cannot remove directory '$File::Find::name': $!\n";
    }
    return;
}
于 2010-04-02T17:16:17.917 に答える
1

Windows用のUNIXツールをダウンロードすれば、何でもできますrm -rv

Perlは多くの目的に最適なツールですが、これは専用のツールを使用した方がよいようです。

于 2010-04-02T19:44:31.040 に答える
0

安価な「クロスプラットフォーム」の方法は次のとおりです。

use Carp    qw<carp croak>;
use English qw<$OS_NAME>;
use File::Spec;  

my %deltree_op = ( nix => 'rm -rf %s', win => 'rmdir /S %s' );

my %group_for
    = ( ( map { $_ => 'nix' } qw<linux UNIX SunOS> )
      , ( map { $_ => 'win' } qw<MSWin32 WinNT>    )
      );

my $group_name = $group_for{$OS_NAME};
sub chop_tree { 
   my $full_path = shift;
   carp( "No directory $full_path exists! We're done." ) unless -e $full_path;
   croak( "No implementation for $OS_NAME!" ) unless $group_name;
   my $format = $deltree_op{$group_name};
   croak( "Could not find command format for group $group_name" ) unless $format;
   my $command = sprintf( $format, File::Spec->canonpath( $full_path ));
   qx{$command};
}
于 2010-04-02T22:38:57.093 に答える