#!/usr/bin/perl # # Copy a file to stdout, with progress metering to stderr. # - Cameron Simpson 18sep2002 # use cs::Misc; use cs::Upd; use cs::Units; use Getopt::Std; sub copyout($;$); $::BSize=65536; $::Type=BINARY; $::Units=CHAR; $::Usage="Usage: $::cmd [-b iosize] [-BDlc] [files...] -b iosize Read/write buffer size. Default: $::BSize -B Use \"binary\" units (default). -D Use \"decimal\" units. -c Count characters (default). -l Count lines. "; $::Xit=0; { my $badopts=0; my %opt; getopts('b:BDcl',\%opt) || ($badopts=1); if (defined $opt{'b'}) { $::BSize=$opt{'b'}+0; } if (defined $opt{'B'}) { $::Type=BINARY; } if (defined $opt{'D'}) { $::Type=DECIMAL; } if (defined $opt{'c'}) { $::Units=CHAR; } if (defined $opt{'l'}) { $::Units=LINE; } die $::Usage if $badopts; } if (! @ARGV) { @ARGV='-'; } for my $f (@ARGV) { if ($f eq '-') { copyout(STDIN) || ($::Xit=1); } else { if (! open(COPYIN, "< $f\0")) { warn "$::cmd: can't read from $f: $!\n"; $::Xit=1; } else { copyout(COPYIN,$f) || ($::Xit=1); close(COPYIN); } } } exit $::Xit; sub human($;$) { my($n,$t)=@_; $t=$::Type if ! defined $t; return scalar( $t eq BINARY ? cs::Units::bytes2human($n,1) : cs::Units::num2human($n,1) ); } sub copyout($;$) { my($FILE,$file)=@_; if (defined $file) { out("$file:"); } my $size = (eval "stat($FILE)")[7]; if (! -f _ || $size < 1) { undef $size; } local($_); my $n; my $off; my $start = time; my $sofar = 0; my $now; my($thruput,$pcnt,$eta); READ: while (defined($n=sysread($FILE,$_,$::BSize)) && $n > 0) { # chuck the data out the back as early as possible WRITE: for ($off=0; $off $start) { $elapsed=$now-$start; $thruput=human($sofar/$elapsed,1)."/s"; } else { $thruput=''; } if (defined $size && $size > 0) { $pcnt=int($sofar*100/$size)."%"; if ($elapsed > 0) { $eta=sprintf("ETA: %6s",scalar(cs::Units::sec2human(int(($size-$sofar)/($sofar/$elapsed)+0.5)))); } else { $eta=''; } } else { $pcnt=''; $eta=sprintf( ($::Units eq CHAR ? "Bytes: %4s" : "Lines: %4s"), human($sofar) ); } out( (defined $file ? "$file: " : '').sprintf("%6s %4s %s",$thruput,$pcnt,$eta) ); } if (($now=time) > $start) { $elapsed=$now-$start; $thruput=cs::Units::bytes2human($sofar/$elapsed,1)."/s"; } else { $thruput=''; } out(''); nl( (defined $file ? "$file: " : '') .sprintf("%6s Size: %s Time: %s", $thruput,human($sofar),scalar(cs::Units::sec2human($elapsed)) ) ); if (! defined $n) { warn "$::cmd: read error: $!\n"; return 0; } return 1; }