Home > database >  Echo progress bar for while external process executing and take STDOUT when it done
Echo progress bar for while external process executing and take STDOUT when it done

Time:02-01

How I can echo a progress bar while an external process is executing and capture its STDOUT when it's done, using only standard modules. And not using fork?

  1. Run external process, something like: @array = `ls -l`;

  2. While it executing, do printing progress bar, like: print '.';

  3. Capture STDOUT of the process into array, when it done

  4. Continue works main script

I'm reading about IPC::Open2, IPC::Open3, but I don't understand how to use them for this task. Maybe it's not the right direction?

CodePudding user response:

What do you have so far? If you have having trouble with the interprocess communication, forget about the progress bar for the moment and ask just about that.

You can't really have a progress bar for something that has an indeterminate end. If you don't know how much input you will read, you don't know what fraction of it you have read. People tend to think of progress bars as a representation of fraction of work done, just not activity. That is, unless you use macOS and understand that "less than one minute" means "more than three hours". ;)

I tend to do something simple, where I output a dot every so often. I don't know how many dots I'll see, but I know that I'll see new ones.

$|  ; # unbuffer stdout to see dots as they are output

while( <$fh> ) {
    print '.' if $. % $chunk_size;  # $. is the line number
    print "\n[$.] " if $. % $chunk_size * $row_length;
    ...
    }

That $fh can be anything that you want to read from, including a pipe. perlopentut has examples of reading from external processes. Those are doing a fork, though. And, the other modules will fork as well. What's the constraint that makes you think you can't use fork?

You can get more fancy with your display by using curses and other things (a carriage return is handy :), but I'm not inclined to type those out.

CodePudding user response:

Perhaps OP is looking for something of next kind just to indicate that external process is running.

Define a handler for $SIG{ALRM} and set alarm 1 to run handler every second. Once process complete reset alarm 0 to turn off alarm handler.

use strict;
use warnings;
use feature 'say';

use Data::Dumper;

my $ls_l;      # variable to store output of external command
$| = 1;        # unbuffered output

$SIG{ALRM} = \&handler;
alarm 1;       # run handler every second

say 'Running sig_alarm_sleep';
$ls_l=`./sig_alarm_sleep`;
say ' done';

alarm 0;

my @fields = qw(rwx count user group size month day time name);
my @lines = split("\n",$ls_l);
my(@array);

for( @lines ) {
    my $x->@{@fields} = split(' ',$_);
    push @array, $x;
}

say Dumper(\@array);

exit 0;

sub handler {
    print '.';
    $SIG{ALRM} = \&handler;
    alarm 1;
}

Bash script sig_alarm_sleep sample

#!/usr/bin/bash

sleep 20
ls -al
  •  Tags:  
  • Related