-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathgzpaste
executable file
·150 lines (122 loc) · 4.62 KB
/
gzpaste
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
#!/usr/bin/perl
use 5.001 ; use strict ; use warnings ;
use Getopt::Std ; getopts '!@:3d:grt:' , \my %o ;
use Term::ANSIColor qw [ :constants color ] ; $Term::ANSIColor::AUTORESET = 1 ;
use autodie qw[ open ] ;
use PerlIO::gzip ;
use FindBin qw[ $Script ] ;
use Time::HiRes qw[ time ] ; # <-- この非標準モジュールが未インストールならどうする?
sub files_open ( ) ;
sub main_body ( ) ;
sub closing ( ) ;
sub cyc_rep ( $ ) ;
$/ = "\r\n" if $o{r} ;
$o{f} //= 0 ; # ファイルが読みと無いときに、何回まで読み直しを許容するか。
$| = 1 if $o{'!'} ;
my $osep = do { $o{d} //= $ENV{osep} // "\t" ; eval qq[qq[$o{d}]] } ; # 出力時の区切り文字
my @FH ; # ファイルハンドラの配列
my $argnum = scalar @ARGV ;
my $out_ln = 0 ; # 出力行数
my $cyc_len = $o{'@'} // 1e5 ; # 何行毎にレポートを発生させるか。
my ( $time00 , $time0 ) = ( time ) x 2 ; # 計算時間測定用
files_open ( ) ;
main_body ( ) ;
closing ( ) ;
exit 0 ;
## 以下は関数。
sub files_open ( ) {
$SIG{INT} = sub { closing ; exit 130 } ;
for ( 0 .. $argnum - 1 ) {
if ( ! $o{g} ) {
open $FH [ $_ ] , '<' , $ARGV [ $_ ] ; # "<:gzip(gzip)"
binmode $FH [ $_ ] , ':gzip(gzip)' ; # < -- 速度比較をせよ。
}
else {
open $FH [ $_ ] , '-|' , 'gzcat' , $ARGV[$_] ; # open $FH, "gzcat '$ARGV[$_]' |" より良いと思った
}
}
}
sub closing ( ) {
# ファイルを閉じる。
close $_ for @FH ;
# 2次情報を標準エラー出力に出力する。
my $sec = time - $time00 ;
$sec = sprintf $o{3} ? '%0.3f' : '%0.0f' , $sec ;
$out_ln =~ s/(?<=\d)(?=(\d\d\d)+($|\D))/,/g ; # 3桁毎にコンマで区切る
print STDERR CYAN $out_ln , " " ;
my $dtfmt = dtfmtlocal () ;
print STDERR GREEN "$out_ln lines output. $sec sec in total ($Script $dtfmt)\n" ;
}
sub main_body ( ) {
my $tolerance = $o{t} ;
while ( 1 ) {
my @out ;
my $readables = 0 ;
for ( 0 .. $argnum - 1 ) {
my $fh = $FH [ $_ ] ;
my $str = <$fh> ;
defined $str ? $readables ++ : ( $str = '' ) ;
push @out , $str ;
}
if ( $readables == 0 ) {
$tolerance -- ;
last if $tolerance < 0 ;
print STDERR RED "An unreadable line occurs after readin $out_ln lines.\n" ;
next
}
chomp @out ; # 各要素について行末の改行文字を除去する。
print "$out_ln:\t" if $o{':'} ; # 行番号の出力
print join ( $osep , @out ) , "\n" ;
cyc_rep ( $out_ln ) if ++ $out_ln % $cyc_len == 0 ; # <-- "++" に要注意。保守時において。
}
}
sub cyc_rep ( $ ) {
local $| = 1 ;
(my$num=$_[0]) =~ s/(?<=\d)(?=(\d\d\d)+($|\D))/,/g ; # 3桁毎にコンマで区切る
my $time_shown = sprintf '%02d:%02d:%02d' , ( localtime ) [2,1,0] ;
my $sec = time - $time0 ;
$sec = sprintf $o{3} ? '%0.3f' : '%0.0f' , $sec ;
$time0 = time ;
print STDERR GREEN $num , ":\t" , $time_shown ;
print STDERR GREEN "\t" , $sec , " sec.\t($Script)" ;
print STDERR RESET "\n" ;
}
sub dtfmtlocal ( ) {
my @f = @{[localtime]}[5,4,3,2,1,0] ;
$f[0] += 1900 ;
$f[1] += 1 ;
return sprintf ( "%04u-%02u-%02u %02u:%02u:%02u" , @f ) ;
}
# ヘルプの扱い
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 some1.gz some2.gz ...
Unixの paste のように、複数のファイルの各行を横に並べる。
オプション:
-d str : 出力の区切り文字
-g ; gzcat コマンドを使ってファイルを読み取るようにする。PerlIO::gzip を読取りに使わない。
-r : 入力の改行が "\r\n" を仮定する。(出力は "\n" のまま。)
-t num : gzファイルが読み取れない場合に何回繰り返して読み取るか。(tolerance)
-3 : 秒数の表示を小数点以下3桁にする。
-! ; 出力をバッファに貯めない。
環境変数 :
$osep : 出力の区切り文字しとして使われるが、-d str で指定すると上書きされる。
利用例:
$0 -d , file1 file2 file3 # -d で出力区切り文字を指定している。
osep=, $0 file1 file2 file3 # 環境変数を出力区切り文字を指定している。
注意点 ;
gzip 圧縮をしたファイルを複数、単純に連結(concat, cat)しても、gzcat では問題無いが
PerlIO::gzipでは問題が起こる。連結時の最初のファイルを読み終わった後、次を読むことができない。
=cut