-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathdirdig
172 lines (148 loc) · 7.02 KB
/
dirdig
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
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
#!/usr/bin/perl
use 5.001 ; use strict ; use warnings ;
use File::Spec::Functions qw[ splitdir splitpath catdir ] ;
use Term::ANSIColor qw[ :constants color ] ; $Term::ANSIColor::AUTORESET = 1 ;
use Getopt::Std ;
use List::Util qw [ minstr maxstr reduce min sum0 sum reduce ] ;
getopts ',.0M:bd:lpv:' , \my %o ;
chdir "$ARGV[0]" or die if @ARGV ;
$| = 1 ;
$o{d} //= 5 ; # どこまでディレクトリを深く潜るか
$o{v} //= 1 ; # 長いpathのうち最後のディレクトリ階層の最後の何個までを出力するか。
my $T = catdir '' , '' ; # ファイルのディレクトリの区切り文字
dig_simple () ;
sub d3 ( $ ) { # -, の指定があれば、数値は3桁ごとに区切る。
my $ret = shift ;
$ret =~ s/(?<=\d)(?=(\d\d\d)+($|\D))/,/g if $o{','} ;
return $ret ;
}
sub getfiles_atdepth ( $ ) {
my $d = (shift) // 1 ; # どの深さを見るか d = depth
my $S = $d >= 0 ? '*' : '..' ; # Symbol
$d = abs $d ;
my $ptn = join $T , $d == 0 ? '.' : ( ($S)x($d-1) , $o{"."} ? ".*" : $S ) ;
$ptn =~ s/\.\.$/..$T*/ ;
print "[$ptn] " if $o{p} ;
return glob "$ptn" ;
}
sub alt_say ( @ ) {
my $f = 1 ;
my @L = map { $f ^= 1 ; $f ? FAINT $_ : $_ } @_ ;
print join " " , @L ;
#print "\n" ;
}
sub uniq ( @ ) { my %s= () ; grep ! $s{$_} ++ , @_ }
sub dig_simple {
my @H = qw [ Depth Non-dir-files Dir-Files ] ;
push @H , "Sum_FileSize_inBytes" if $o{b} ;
if ( $o{M} ) {
push @H, YELLOW "[File-numbers of sub-directories that are among the most]" ;
push @H, "Such sub-directories .." ;
}
else {
push @H , (CYAN "NonDirFile-examples")."..", (GREEN "DirFile-examples").".." if $o{v} > 0 ;
}
print +join ("\t" , @H ) . "\n--\n" ;
my @dep = $o{d} >= 0 ? ($o{0} ? 0:1) .. $o{d} : reverse $o{d} .. ($o{0} ? 0:-1) ;
for ( @dep ) {
my @files = getfiles_atdepth $_ ;
#@files = grep { my $t = (splitdir $_)[-1] ; $t =~ m/\A\./ } @files if $o{"."} ;
@files = grep { ! m/(\A|$T)\.{1,2}\Z/ } @files if $o{"."} ;
my @dirfiles = grep { -d $_ and $_ .= "" } @files ;
my @ndfiles = grep { ! -d } @files ;
my $dL = grep { -l } @dirfiles ;
my $nL = grep { -l } @ndfiles ;
my @out ;
push @out , "$_:" ;
push @out , do { my $tmp = scalar @ndfiles ; $tmp .= FAINT "($nL)" if $nL ; d3 $tmp } ;
push @out , do { my $tmp = scalar @dirfiles ; $tmp .= FAINT "($dL)" if $dL ; d3 $tmp } ;
push @out , do { $_ = sum0 map -s // 0 , @ndfiles ; d3( $_ ) } if $o{b} ;
print join "\t" , @out ;
if ( defined $o{M} ) {
my @dirs0 = @dirfiles ; # ここでコピーをしないと支障が
my @fnums = map { opendir my $dh,$_ or print RED $_ ; my @t = readdir $dh ; closedir $dh ; scalar @t } grep { -r } @dirs0 ;
my @t = splice @{ [ sort { $b->[1] <=> $a->[1] } map {[$_,$fnums[$_]]} 0 .. $#fnums ] } , 0, $o{M} ;
print YELLOW "\t[". ( join ", " , map {$_->[1]} @t ) . "]\t" ;
alt_say map { $dirs0[ $_ -> [0] ] } @t ;
print "\n" ;
last if @dirfiles == 0 && ! $o{'.'} && $o{d} > 0 ;
next ;
}
print "\n" and next if $o{v} == 0 ; # <-- v == 0 の場合の特殊処理
print "\t" ;# , color("cyan") ;
my @R = () ;
push @R , & rep ( @ndfiles ) ;
grep { $_ = CYAN & botD ($_) } @R ;
alt_say @R ;
print "\t" ;
@R = () ;
push @R , & rep ( @dirfiles ) ;
#print RED ":" , scalar @R ;
grep { $_ = GREEN & botD ($_) . '/'} @R ;
alt_say @R ;
print color ("reset") ;
print "\n" ;
last if @dirfiles == 0 && ! $o{'.'} && $o{d} > 0 ;
}
}
sub botD( $ ) { # 区切りでsplitして下から$o{v}個のみ取り出して再連結
my @t = splitdir shift ;
my @t1 = splice @t , - min( scalar @t , $o{v} ) ;
my $i = $o{d} >= 0 ? '-' : '^' ;
@t = @t ? $i x @t : () ;
return join $T , @t , @t1 ;
}
sub rep ( @ ) { # 代表値の意味。文字列長が最小のものと最大のものも取り出したい
sub sd { splitdir shift } ;
sub len { length shift } ;
my @L = () ;
#print RED join ":" , @_[0] ;
#no warnings ;
if ( 1 or ! $o{l} ){
push @L , reduce { (sd $a)[-1] lt (sd $b)[-1] || $a lt $b ? $a : $b } grep {$_ } @_ ;
push @L , reduce { (sd $a)[-1] gt (sd $b)[-1] || $a gt $b ? $a : $b } grep { $_ } @_ ; # grep {$_ ne $L[0]} @_ ;
}
#no warnings ;
if ($o{l}) {
push @L ,reduce { len ((sd $a)[-1]) < len((sd $b)[-1]) || (sd $a)[-1] lt (sd $b)[-1] ? $a : $b } grep { $_ ne $L[0] and $_ ne $L[1] } grep $_ , @_ ;
push @L ,reduce { len ((sd $a)[-1]) > len((sd $b)[-1]) || (sd $a)[-1] gt (sd $b)[-1] ? $a : $b } grep { $_ ne $L[0] and $_ ne $L[1] and $_ ne $L[2] } grep $_ ,@_ ;
# 上記で grep が本質的に必要か?
}
#print RED 100*scalar @_ ;
return uniq grep { defined } @L ;
}
## ヘルプの扱い
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 ;
exit 0 ;
}
=encoding utf8
=head1
$0 [dirname]
カレントディレクトリの n (n=1,2,3.. ) 階層下のディレクトリにある、
非ディレクトリファイルの個数とディレクトリの個数を出力する。
それらの個数について、それらの内のリンクファイルを括弧内に出力する。
dirname が指定された場合は、そのディレクトリを起点に調べる。
内部動作上の注意点 :
ファイルの探索は,3階層下のディレクトリのファイルであればワイルドカードで */*/* のような探し方をしていいて、
そのため、シンボリックリンクファイルの先がディレクトリの場合、そこから先は探さないことが通常起こる。
なお、$0 の引数で dirname を指定した場合は、一旦そこにchdirするので、その先は読む。
オプション ;
-d N : 何階層下まで潜るかを指定する。未指定なら5と見なす。負の数を指定すると親ディレクトリの方向に上がっていく。
-b : 各階層についての、非ディレクトリファイルについての、バイト数の合計も出力する。
-v N : N > 0 の場合、具体的なファイル名の例(文字列としての最小値と最大値)も出力。各パスは右からN階層に制限される。
-l : ファイル名を出力する場合に、ファイル名の部分が文字列長として最小のものと最大のものも出力される。
-. : 隠しファイルについて調べる。
-0 : 起点の直下から下の方向へ見ていくのではなくて、起点自身から下の方向に見ていく。
-p : 探索したパターン(どんなワイルドカードを使ったか)を表示する。
-M N ; 各階層において、最もファイルを持つディレクトリを、その階層からN個見つけ出す。
-, : 出力する数値について、3桁ごと(1000進数として)区切るようにする。
=cut