#!/usr/bin/perl
use 5.008 ; use strict ; use warnings ;
use Getopt::Std ; getopts ".:bc:dgsw:z:" , \my %o ;
use Time::HiRes qw[ gettimeofday tv_interval sleep ] ; # Perl 5.7.3からコアモジュール
use Term::ANSIColor qw[ color :constants ] ; $Term::ANSIColor::AUTORESET = 1 ;
use FindBin qw[ $Script ] ;
sub FB ($){FAINT BOLD $_[0]}
sub Y ($){YELLOW $_[0]}
my ($t0s,$t0p) = gettimeofday ; # 「起動した時刻」の記録。15マイクロ秒のオーバーヘッド
$ENV{TZ} = $o{z} if exists $o{z} ;
sub TSTP { local $|=1 ;say STDERR CYAN "$. line(s) output so far. ($Script)" ; $SIG{TSTP} ='DEFAULT' ; kill 'TSTP', $$ } ;
$SIG{TSTP} = sub { TSTP } ;
$SIG{CONT} = sub { $SIG{TSTP} = sub { TSTP } } ;
$| = 1 unless $o{b} ;
$o{'.'} //= 3 ;
do { & proc_w ; exit } if defined $o{w} ;
my $dig = $o{'.'} if $o{'.'} ; # 桁数 (表示する秒の小数点以下の桁数)
my $lay = 1e6 / 10 ** $dig if defined $dig ; # lay は英語の「置く」のつもり。
my $HMS = '%02d:%02d:%02d' ; # 何度も使われる書式
* gapproc = $o{g} ? sub (){ ($t0s, $t0p) = gettimeofday } : sub (){} ; # 50ナノ秒のオーバーヘッド。1回の実行につき。
do { & main ; exit } ;
sub proc_w () {
while ( <> ) {
do { my $s = "$o{w}" * $. - tv_interval( [$t0s,$t0p] , [gettimeofday] ) ; sleep $s > 0 ? $s : 0 } ;
print $_ ; # print は 2 〜 5 ミリ秒動作に時間がかかる。
}
}
sub hhmmss0 () { sprintf $HMS , @{[localtime]}[2,1,0] }
sub hhmmssD () { my($s,$m)=gettimeofday ; sprintf "$HMS.%0${dig}d",@{[localtime $s]}[2,1,0],int $m/$lay }
sub ymdhms () { my @f=localtime;$f[4]+=1;$f[5]+=1900 ; sprintf "%02d-%02d-%02d $HMS" , @f[5,4,3,2,1,0] }
sub secondsSince0 () { return sprintf "%0.0f" , time - $t0s }
sub secondsSinceD () { return sprintf "%0.${dig}f" , tv_interval [ $t0s, $t0p ] }
sub timenow () {
my $t1 = $o{d} ? ymdhms : defined $dig ? hhmmssD : hhmmss0 ;
my $t2 = $dig ? secondsSinceD : secondsSince0 ;
"$t1 $t2" ;
}
sub main () {
* timenow = $o{d} ? * ymdhms : defined $dig ? * hhmmssD : * hhmmss0 ;
* timenow = $o{'.'} ? * secondsSinceD : * secondsSince0 if $o{s} || $o{g} ;
my $C = defined $o{c} ? $o{c} eq 0 ? '' : color $o{c} : color 'faint bold' ;
my $R = defined $o{c} ? $o{c} eq 0 ? '' : color 'reset' : color 'reset' ;
while (<>) { my $t = timenow ; print "$C$t$R\t$_" ; & gapproc } ;
}
## ヘルプの扱い
sub VERSION_MESSAGE {}
sub HELP_MESSAGE{
use FindBin qw[ $Script ] ;
$ARGV[1] //= '' ;
open my $FH , '<' , $0 ;
while(<$FH>){
s/\$0/$Script/g ;
print $_ if $ARGV[1] eq 'opt' ? m/^\ +\-/ : s/^=head1// .. s/^=cut// ;
}
close $FH ;
exit 0 ;
}
=encoding utf8
=head1
timeput
入力を1行ずつ読み、その各行の先頭に、読み取った時点の時刻をタブ区切りで出力する。
ただし、"-w 秒数" の指定により、1行読んで出力して、指定秒数動作を止める(sleepする)。
オプション :
-b : 出力のバッファリングを許す(何か理由が無い限り使うことは無いであろう)
-c STR : 色の指定。0で色無し。"cyan","faint red bold","bright_blue"など。色名指定はTerm::ANSIColor を参照。
-d : 日付も出力。yyyy-mm-dd HH:MM:SS 形式で。(date)
-g : 開始からの秒数でなくて、1行ごとの間隔秒数を表示。(gap)
-s : 起動してからの秒数を出力。(start)
-w N: 入力から1行ずつ逐次読み取り出力して、N秒停止することを繰り返す。正の浮動小数点数を指定可能。(wait)
-z STR : タイムゾーンの設定。"Asia/Tokyo", "-9", "-9:00", "JST-9" などが設定できる。(システム依存)
-. N : 秒数を小数点以下 N 桁出力する。0から6の整数値が使える。未指定なら3。(-d とは両立しない。)
利用例 :
yes | head | timeput -.6
yes | head | timeput -d | sed 's/ /T/' # POSIXの日時形式にしたい場合。このsed文は最初の空白文字のみTに変更。
seq 5 | timeput -.6 | timeput -s.6 | timeput -g.6
seq 10 | timeput -w0.45 | timeput -g.3 # 0.45秒ずつ1行を読み取る。
command 1> output1.txt 2> >( timeput error.log ) # command は標準エラー出力に何か出力をするプログラムである。便利。
開発メモ:
* -w の動作を高度化したい。-w 2,0.2x10,0 と指定することで最初は2秒、次に10回は0.2秒、残りは即座のように。,は+、xは*でも可としたい。
* -3 のオプションを作りたい。timeput -3 で timeput -g | timeput -s | timeput とおなじ機能を持たせたい。
* 名前を timeput (タイムプット)ではなく、puttime の方が「プッタイム」で発音しやすい気がする。その方が記憶しやすい。
=head1 AUTHOR
下野寿之 Toshiyuki SHIMONO <bin4tsv@gmail.com>
=head1 COPYRIGHT AND LICENSE
Copyright (c) 2021 Toshiyuki SHIMONO. All rights reserved.
This program is free software; you can redistribute it and/or
modify it under the same terms as Perl itself.
=cut