Hi,

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:

  • run an external command (e.c.) and dispaly some kind of "notification" to the user (that - yes - has nothing to do with how "far" the e.c. actually is)
  • capture output AND exit value from the e.c.

    the current design is as follows

  • the sub forks.
  • the child runs the command via open-pipe
  • the parent outputs some kind of progress bar
  • child communicates output and exit value via pipes to the parent
  • parent outputs the retrieved stuff after the child has exited

    My code works fine for some commands, but - for whatever reason - not for all of them.

    ($result, $exitcode) = run_w_progress(1, 'for i in `seq -w 4`; do slee +p 3; /bin/echo $i; done');
    returns
    Result: 1 2 3 4 Exitcode:0 finishing ...
    whereas
    ($result, $exitcode) = run_w_progress(1, '/bin/echo -e "foo\nbar"');
    only returns (note the missing 'bar')
    Result: foo Exitcode:0 finishing ...

    Here's my code (fully working example):
    #!/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";

    Any hints greatly appreciated!
    svenXY

    Todo: Make this also work with STDERR and such...


    In reply to external command, progress bar and exit value by svenXY

    Title:
    Use:  <p> text here (a paragraph) </p>
    and:  <code> code here </code>
    to format your post, it's "PerlMonks-approved HTML":



  • Posts are HTML formatted. Put <p> </p> tags around your paragraphs. Put <code> </code> tags around your code and data!
  • Titles consisting of a single word are discouraged, and in most cases are disallowed outright.
  • Read Where should I post X? if you're not absolutely sure you're posting in the right place.
  • Please read these before you post! —
  • Posts may use any of the Perl Monks Approved HTML tags:
    a, abbr, b, big, blockquote, br, caption, center, col, colgroup, dd, del, details, div, dl, dt, em, font, h1, h2, h3, h4, h5, h6, hr, i, ins, li, ol, p, pre, readmore, small, span, spoiler, strike, strong, sub, summary, sup, table, tbody, td, tfoot, th, thead, tr, tt, u, ul, wbr
  • You may need to use entities for some characters, as follows. (Exception: Within code tags, you can put the characters literally.)
            For:     Use:
    & &amp;
    < &lt;
    > &gt;
    [ &#91;
    ] &#93;
  • Link using PerlMonks shortcuts! What shortcuts can I use for linking?
  • See Writeup Formatting Tips and other pages linked from there for more info.