Last active
October 21, 2022 17:37
-
-
Save sebkirche/b371e82be413c49afb184361a8738d1e to your computer and use it in GitHub Desktop.
simple pure Perl pipe viewer similar to pv. hacked to replace Number::Bytes::Human::format_bytes by a simpler formatter
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/usr/bin/env perl | |
=encoding utf8 | |
=head1 NAME | |
Pure perl pipe viewer | |
=head1 VERSION | |
Version 1.3 | |
=cut | |
our $VERSION = '1.3'; | |
=head1 SYNOPSIS | |
This is a pure perl pipe viewer to view progress of data being piped through STDIN to STDOUT. It is similar to the 'pv' command line tool. | |
Why? I needed 'pv' on MacOS and didn't want to bother installing ports. | |
=head1 USAGE | |
./ppv.pl <INPUTFILE >OUTPUTFILE | |
cat BIGFILE | gzip | ./ppv.pl | ssh somehost "gunzip | someothercomand >blargh" | |
=head1 AUTHORS | |
Mark Steele, C<< <mark at control-alt-del.org> >> | |
Sébastien Kirche, C<< <sebastien.kirche at free.fr> >> | |
=cut | |
use IO::Select; | |
use Time::HiRes qw(time); | |
# use Number::Bytes::Human qw(format_bytes); | |
use strict; | |
if ($#ARGV > -1 && ($ARGV[0] eq '-h' || $ARGV[0] eq '--help')){ | |
print <<"USAGE"; | |
Pure Perl Pipe Viewer v$VERSION Mark Steele & Sebastien Kirche | |
Pipe STDIN to STDOUT and display some statistics about the rate of flow. | |
Examples: $0 < some_file | command | |
some_command | $0 | other_command | |
nc some_host some port | $0 > some_file | |
USAGE | |
exit 0; | |
} | |
my $s = IO::Select->new(); | |
my $size = (stat(STDIN))[7]; | |
$s->add(\*STDIN); | |
my $count = 0; | |
my $bytes = 0; | |
my $time = my $start = time(); | |
my $totalbytes = 0; | |
my $BAR_LENGTH = 35; | |
while ($s->can_read()) { | |
my $ret = sysread(STDIN,my $buf, 32768); # read chunks of 32kB | |
if ($ret == 0) { | |
total(); | |
} | |
my $now = time(); | |
$bytes += $ret; | |
$totalbytes += $ret; | |
if (($now - $time) >= 0) { | |
if ($size){ | |
# total size is known | |
my $msg = sprintf "\r\rThroughput: %9s/sec, total transferred: %9s of %9s (%.02f\%) ", | |
humanize_bytes($bytes/($now-$time)), | |
humanize_bytes($totalbytes), | |
humanize_bytes($size), | |
($totalbytes/$size)*100; | |
print STDERR $msg; | |
print STDERR progress_bar($totalbytes, $size, $BAR_LENGTH); | |
} else { | |
#total size unknown | |
printf STDERR "\r\rThroughput: %9s/sec, total transferred: %d (%9s) ", | |
humanize_bytes($bytes/($now-$time)), | |
$totalbytes, | |
humanize_bytes($totalbytes); | |
} | |
$time = $now; | |
$bytes = 0; | |
} | |
my $written = 0; | |
while ($written != $ret) { | |
$written += syswrite(STDOUT,$buf,$ret-$written,$written); | |
} | |
} | |
total(); | |
sub total { | |
my $now = time(); | |
printf STDERR "\nBytes: %s (%s/sec) in %.02f seconds\n", | |
humanize_bytes($totalbytes), | |
humanize_bytes($totalbytes/($now-$start)), | |
($now - $start); | |
exit; | |
} | |
# quick and dirty local version to display understandable sizes | |
# for mere humans than cannot read sizes in bytes | |
sub humanize_bytes { | |
my $len = int(shift); | |
my $r; | |
if ($len >= 2 ** 30){ | |
$r = sprintf("%.1f GiB", $len / 2 ** 30); | |
} elsif ($len >= 2 ** 20){ | |
$r = sprintf("%.1f MiB", $len / 2 ** 20); | |
} elsif ($len >= 2 ** 10){ | |
$r = sprintf("%.1f KiB", $len / 2 ** 10); | |
} else { | |
$r = $len; | |
} | |
return $r; | |
} | |
sub progress_bar { | |
my ($progression, $total, $width) = @_; | |
my $pchars = $width / $total * $progression; | |
my $pct = 100 / $total * $progression; | |
my $bar = sprintf("%s%s %.1f%%", | |
'#' x int($pchars), | |
'.' x ($width - int($pchars)), | |
$pct); | |
return $bar; | |
} | |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment