-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathsamesize
121 lines (98 loc) · 4.27 KB
/
samesize
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
#!/usr/bin/perl
use 5.014 ; use strict ; use warnings ;
use feature qw [ say ] ;
use Time::HiRes qw[gettimeofday tv_interval] ;
use Term::ANSIColor qw [ :constants color ] ; $Term::ANSIColor::AUTORESET = 1 ;
use File::Spec::Functions qw[ catfile splitdir rel2abs updir ] ;
use Getopt::Std ;
use List::Util qw [ max min sum sum0 reduce uniq ] ;
use Cwd qw [ getcwd abs_path ] ;
use POSIX qw[ strftime ] ;
#use Digest::SHA1 qw[ sha1 sha1_hex sha1_base64 ];
use Digest::MD5 qw(md5 md5_hex md5_base64);
sub dtwhen ( $ ) ;
my $time_start = [ gettimeofday ] ;
my $t0 = $time_start -> [0] ;
#say dtwhen ( $t0 ) ;
getopts '0:2b:Df:nos' , \my%o ;
my @files = @ARGV ? @ARGV : glob '*' ;
$o{2} = 1 if $o{D} ; # <--- 要注意。 不用意のこの行はコメントアウトや除去をしないように。
$o{0} //= 1 ; # <--- 要注意。 不用意のこの行はコメントアウトや除去をしないように。
& main ;
exit 0 ;
END{ print RESET "" } ;
sub main () {
my %s2f ;
for ( @files ) {
next if -d $_ ;
my $size = ( lstat $_ ) [7] ; # <-- -- lstat で良いのか
next if defined $o{b} && $size < $o{b} ;
push @{$s2f{$size}} , $_ ;
my @out = ( $size , $_ ) ;
#say join "\t" , @out ;
}
my $least = $o{f} // 2 ; # ? 1 : 2 ;
my @sizes = sort {$a<=>$b} grep { @{ $s2f { $_ } } >= $least } keys %s2f ;
my $nfmt = do { my $t = max @sizes , 0 ; my $d = length "$t" ; "%${d}s" } ; # <-- %${d}u ??
for my $size ( @sizes ) {
#next if @{ $s2f{$size} } == 1 ;
my @files = sort @{ $s2f{$size} } ; # ファイルの一覧
@files = sort {(stat $a)[9] <=> (stat $b)[9] } @files if $o{n} // $o{o} ;
@files = reverse @files if $o{n} ;
my %seenD ; # 既に見たハッシュダイジェスト値
for ( @files ) {
my @t3 = (stat $_)[8,9,10] ; # <-- stat にしたのを便宜上の変更
my $ctx = Digest::MD5->new;
unless ($o{0}){
open my $FH, '<', $_ or die "Can't open '$_': $!";
binmode $FH ;
$ctx->addfile( $FH );
#while ( <$FH> ) { $ctx -> add ( $_ ) }
close $FH ;
}
utime @t3[0,1] , $_ unless $o{0} ; # <- -- --- 時刻情報を破壊するので注意。もしくは秒の小数点以下の情報が消える。
my $digest = $o{0} ? '---' : $ctx->hexdigest ;
next if $o{2} && ! $seenD{ $digest } ++ ;
if ( $o{D} && ! $o{0} ) { unlink $_ ; next } ;
my @out = ( sprintf ($nfmt , $size) , $digest , map ( dtwhen $_ , @t3 ) , $_ ) ;
say join "\t" , @out ;
}
}
}
sub dtwhen ( $ ) {
my $fmt = abs ( $_[0] - $t0 ) >= 86400 * 180 ? '%Y-%m-%d' : $o{s} ? '%m-%d %H:%M:%S' : '%m-%d %H:%M';
strftime $fmt , localtime $_[0] ;
}
END{
exit if exists $o{v} && $o{v} eq "0" ;
say STDERR " -- " , REVERSE ITALIC " Process time: " , CLEAR " " ,
sprintf( "%.6f", tv_interval $time_start , [ gettimeofday ] ) , " second(s)." ;
}
## ヘルプの扱い
sub VERSION_MESSAGE {}
sub HELP_MESSAGE {
use FindBin qw[ $Script ] ;
$ARGV[1] //= '' ;
open my $FH , '<' , $0 ;
while(<$FH>){
s/\$0/$Script/g ;
print $_ if s/^=head1// .. s/^=cut// and $ARGV[1] =~ /^o(p(t(i(o(ns?)?)?)?)?)?$/i ? m/^\s+\-/ : 1;
}
close $FH ;
$o{v} = 0 ;
exit 0 ;
}
=encoding utf8
=head1
このコマンドについては、ファイルの時刻情報を書き換えたり、消去する機能があるのに、デバグなどが不十分なので、
その危険性を理解して使うこと。
$0 files ..
オプション:
-0 0 : MD5ハッシュ値を算出する。ファイルのアクセス時刻やinode時刻を変える危険を確認する効果がある。
-b N : 処理対象とする最小のバイトサイズを指定。0バイトファイルを避けるなら1を指定。
-f N : 少なくとも何回出現したものだけを取り出すかの指定。初期値は2。
-n : 同じファイルサイズなら書換日時の新しい順 (newer)
-o : 同じファイルサイズなら書換日時の古い順 (older)
-s : 180日以内について、日時情報は秒単位で表示。
-2 : 同じファイルサイズで,同じハッシュ値のものについて、2番目以降を取り出す。
-D : 同じファイルサイズで,同じハッシュ値のものについて、2番目以降をファイル除去する。<-- 破壊的, 危険