電子書籍の厳選無料作品が豊富!

Perl で特定のフォルダ以外を削除したいのですが
普通はフォルダを指定して削除するところを

rmdir "log/delete";

上記のように削除させますが

ディレクトリ構造↓
log----1/
-------2/
-------3/
-------4/
-------5/
-------delete/
-------log.txt

上記のlog.txtの中身↓
1
2
3
4
5
-------------------
のように連番が振ってあり
その連番と同じフォルダがなければ削除

と今回の場合
deleteフォルダがないので
それを削除させたいのですが、
rmdir "log/delete";
↑これではなく

1,2,3,4,5を残し、それ以外のフォルダを削除
という指定にしたいのですが

どのようにすればいいでしょうか?

A 回答 (6件)

さすがに #1 に書いたようなスクリプトだと保守性が悪すぎるので, 最後の


remove_tree grep { -d; } map { "$parent_dir/$_"; } grep { my $f = $_; $f ne "." && $f ne ".." && ! grep { $_ eq $f; } @preserve_dirs; } readdir DH;

for my $f (readdir DH) {
next if $f eq '.';
next if $f eq '..';
next if grep { $_ eq $f; } @preserve_dirs;
my $d = "$parent_dir/$f"; #ここも File::Spec::catfile を使う方が安全?
remove_tree $d if -d $d;
}
くらいのループにすべきですけどね. あれは
その気になればこのくらい圧縮できる
という (無意味かつ悪い) 実例ですから.
    • good
    • 0
この回答へのお礼

なるほどなるほど

一度フォルダ内のリストを取得させ
そこから「.」「..」をまずはぶき
フォルダ内=配列のものをgrepさせ

最後にリストに内ものを削除するのですね!

File::Spec::catfil
↑初めて見ました
↓これですね。。
http://search.cpan.org/~xsawyerx/PathTools-3.74/ …

おおよそ理解できてきたので、↑のモジュールは自分と勉強して
使えるようにしたいと思います!


ありがとうございました!!

お礼日時:2018/03/23 13:14

正直にいわせてもらうと, grep や map を理解していないんじゃないかなと思う.



あと「前回の処理だと1つのファイルしか削除されなかった」はなにかを勘違いしてるんじゃないだろうか. 少なくとも手元ではちゃんと「log.txt に書かれていないディレクトリ」を一度で全部消してる.
    • good
    • 0
この回答へのお礼

たしかにそうでした。
ただ、上手く説明できませんが・・・


@preserve_dirs
この子が対象だということですね

use File::Path;

use File::Path 'remove_tree';

これにするだけで解決でした。
ここまでの仮定で、余計なForを入れてるからおかしなことになっていたのですね。

お礼日時:2018/03/22 16:34

え.... 問題ないというか, ほぼ「問題しかない」んですが....



何をやっているか, 理解できていますか? 自分の言葉で説明できますか?
    • good
    • 0
この回答へのお礼

なんですって・・・;;
まだまだ理解できてませんねorz

my $parent_dir = "log";
my @preserve_dirs;
open FH, "$parent_dir/log.txt";
chomp(@preserve_dirs = <FH>);
#▲ここで、log.txtの中身を取得

my $dir_serch="./log/";
my @Kosu;
opendir(DIR, "$dir_serch");
my @file = readdir(DIR);

foreach (@file) {
push @Kosu , "$_\n";
}
closedir(DIR);
#▲無理やりではありますが、フォルダ内の名前を取り出し
#▼下のループの最後まで $#Kousu = [.][..]も含んだままなので
#ループ処理が多くなってますが。。

for(my $fd=0;$fd<=$#Kosu;$fd++){
opendir DH, $parent_dir;
remove_tree grep { -d; }
map { "$parent_dir/$_"; }
grep { my $f = $_; $f ne "." && $f ne ".." &&
! grep { $_ eq $f; } @preserve_dirs; } readdir DH;
closedir DH;
}
#質問には含めていませんでしたが、
#前回の処理だと1つのファイルしか削除されなかったので、
#複数消したかったため、ループ処理を加えておりました・・・

お礼日時:2018/03/20 09:32

動作はそれで OK のはず. ただし


http://perldoc.perl.org/File/Path.html
によると rmtree は古い形式 (超意訳) なので, そこは remove_tree の方が安全かと.

grep や map は
・grep: 配列から指定した条件を満たす要素を取り出し配列として返す
・map: 配列の各要素に対して処理した結果を配列として返す
という動作.

それからついでに
chomp(@preserve_dirs = <FH>);

%preserve_dirs = ('.' => 1, '..' => 1, map { chomp; $_ => 1; } <FH>);
のようにハッシュにしておけばあとの
grep { my $f = $_; $f ne "." && $f ne ".." && ! grep { $_ eq $f; } @preserve_dirs; } readdir DH

grep { ! $preserve_dirs{$_}; } readdir DH
と短縮できることに一晩寝て気付いた.

と書いておくけど, 本当に実用とするのであればこんなに grep や map をばんばか使うんじゃなくっててきせつなループにすべきだと思う.
    • good
    • 0
この回答へのお礼

なるほど!
ただ、ハッシュの仕組みが未だに理解できていないので、今は使わないようにしておきます・・・

ループ処理をヒントに
最終的に
use strict;
use warnings;
use File::Path 'remove_tree';

my $parent_dir = "log";
my @preserve_dirs;
open FH, "$parent_dir/log.txt";
chomp(@preserve_dirs = <FH>);

my $dir_serch="./log/";
my @Kosu;
opendir(DIR, "$dir_serch");
my @file = readdir(DIR);

foreach (@file) {
push @Kosu , "$_\n";
}
closedir(DIR);

for(my $fd=0;$fd<=$#Kosu;$fd++){
my $Ko = $Kosu[$fd];
opendir DH, $parent_dir;
remove_tree grep { -d; }
map { "$parent_dir/$_"; }
grep { my $f = $_; $f ne "." && $f ne ".." &&
! grep { $_ eq $f; } @preserve_dirs; } readdir DH;
closedir DH;
}


close FH;

このようになりましたが、問題ないでしょうか・・・?

お礼日時:2018/03/19 09:47

直すのはもちろん直せるんだけど, どのようなことをしようとしているか理解できているのですか?

    • good
    • 0
この回答へのお礼

ある程度は理解しているつもりではありますが・・・
自信はありません・・・

$parent_dir = "log";
open FH, "$parent_dir/log.txt";
chomp(@preserve_dirs = <FH>);
close FH;

これはログテキスト内の列を取得し、配列へ

でもここがわからないです

remove_tree grep { -d; }
↑これはわからない
フォルダを削除だと思うのですが、初めて見ました・・・→「remove_tree」
map { "$parent_dir/$_"; }
↑これもわからない
?log/ ←内のフォルダのリスト化?
grep { my $f = $_; $f ne "." && $f ne ".." && ! grep { $_ eq $f; } @preserve_dirs; }
おそらくこれする前を、print表示すると
----------------------------------------
.
..
1
2
3
4
5
delete
----------------------------------------
↓これを
----------------------------------------
1
2
3
4
5
----------------------------------------
[.][..]はフォルダーパス取得したときに付与されている?のと
! grep { $_ eq $f; } ログファイル内と、フォルダリストがイコールでないやつ
ということでしょうか?

初めてみた→「remove_tree」
でググっているうちに
↓にたどり着き

use File::Path; → use File::Path 'rmtree';
remove_tree → rmtree

に変更させると実行はできたのですが、
正しいでしょうか?

お礼日時:2018/03/17 09:10

use File::Path;


$parent_dir = "log";
open FH, "$parent_dir/log.txt";
chomp(@preserve_dirs = <FH>);
close FH;
opendir DH, $parent_dir;
remove_tree grep { -d; } map { "$parent_dir/$_"; } grep { my $f = $_; $f ne "." && $f ne ".." && ! grep { $_ eq $f; } @preserve_dirs; } readdir DH;
closedir DH;

みたいな感じ?
    • good
    • 0
この回答へのお礼

ソースご掲示ありがとうございます。

実行してみたのですが
下記のようなエラーがでたのですが、
Use of my $_ is experimental at test.pl line 7.
Use of my $_ is experimental at test.pl line 7.
syntax error at test.pl line 7, near "remove_tree
grep"
syntax error at test.pl line 7, near "; }"
Execution of test.pl aborted due to compilation er
rors.

どういうことでしょうか・・?

お礼日時:2018/03/16 14:17

お探しのQ&Aが見つからない時は、教えて!gooで質問しましょう!