svenXY has asked for the wisdom of the Perl Monks concerning the following question:
I know that questions about progress bars have been answered here before, but they did not seem to address my special case here (forgive me if I'm wrong). Anyway, I tried to roll my own solution that works partly, but I ran into some trouble.
Here's what I try to achieve:
the current design is as follows
My code works fine for some commands, but - for whatever reason - not for all of them.
returns($result, $exitcode) = run_w_progress(1, 'for i in `seq -w 4`; do slee +p 3; /bin/echo $i; done');
whereasResult: 1 2 3 4 Exitcode:0 finishing ...
only returns (note the missing 'bar')($result, $exitcode) = run_w_progress(1, '/bin/echo -e "foo\nbar"');
Here's my code (fully working example):Result: foo Exitcode:0 finishing ...
#!/usr/bin/perl use strict; use warnings; use POSIX ":sys_wait_h"; use IO::Select; use IO::Handle; my ($result, $exitcode) = run_w_progress(1, 'for i in `seq -w 4`; do s +leep 3; /bin/echo $i; done'); print "Result:\n",$result,"\nExitcode:",$exitcode,"\n"; + ($result, $exitcode) = run_w_progress(1, '/bin/echo -e "foo\nbar"'); print "Result:\n",$result,"\nExitcode:",$exitcode,"\n"; sub run_w_progress { my ($sleep, $cmd) = @_; my($reader, $writer); pipe $reader, $writer; my($reader2, $writer2); pipe $reader2, $writer2; $writer->autoflush(1); $writer2->autoflush(1); my @watch = qw(| / - + \ | / - \ |); my $pos = 0; $|++; if ( fork()) { my $kid; my $output = ''; my $exitval; my $c=0; my $handles = IO::Select->new(); $handles->add($reader, $reader2); do { sleep $sleep; my @fhs; while (@fhs = $handles->can_read(0)) { for my $fh (@fhs){ if (fileno($fh) == fileno($rea +der)) { my $line = scalar <$re +ader>; $output .= $li +ne; } else { $exitval = sca +lar <$reader2>; chomp $exitval +; } } } print "\r",'|'x$pos,$watch[$c++]; if ($c == 10) { $c=0; $pos++; } $kid = waitpid(-1, WNOHANG); } until $kid > 0; print "|\n"; return ($output, $exitval); } else { open(my $pipe, '-|', $cmd); while (<$pipe>) { # pass output line to parent print $writer $_; } close $pipe; close $writer; # pass exit value to parent print $writer2 $?>>8, "\n"; close $writer2; exit 0; } } print "finishing ...\n";
Todo: Make this also work with STDERR and such...
|
---|
Replies are listed 'Best First'. | |
---|---|
Re: external command, progress bar and exit value
by almut (Canon) on Apr 01, 2009 at 15:17 UTC | |
by svenXY (Deacon) on Apr 02, 2009 at 06:34 UTC |