On Wed, 25 Apr 2001, Jeff Shanholtz wrote:

> I want to run a command and pipe its output to my perl script (`command`
> won't work because the command takes a long time and produces tons of
> output). However, I really need to know the exit code when it's done
> (ala system()/256). Is it possible? I'm not finding much help in the
> documentation. Can this be done?

Here's something I extracted from one of my production programs.
I had to rewrite it a little to get rid of the application specifics,
and it has had minimal testing.
Make sure you pass in the complete path in command_path arg for
the argument you want to execute.

For example this works:
c:/perl/bin/perl.exe

This will not work:
c:/perl/bin/perl

I'm on Win2k so if your on a win9x machine, you might have to
play with the path separators.

Be warned! Things like this can hang. I have not had this happen
with the programs I run with this, but...

Hope this helps.

###################Clip Here###################################
#!/perl/bin/perl
package run_process;
use strict;
use Win32::Process;
use IO::Handle;
use constant RP_OPTIONAL_ARG => 1;
use constant RP_REQUIRED_ARG => 2;
use Class::MethodMaker
        new => [ qw /new/ ],
  get_set => [ qw /
                command_path
                command_args
                run_dir
                perlinecallback
        / ],
        list => [ qw /errors/];

sub perLineCheck {
        my ( $self ) = @_;
        my $callback = $self->perlinecallback( );
        if ( $callback ) {
                &$callback( @_ )
        } else {
                return 0;
        }
}

sub check_params {
        my ($self, $valid_params, $params) = @_;
        my $param;
        my $val;
        my $error_in = 0;
        # If parameters passed in are valid set object attribute to value.
        while (($param, $val) = each %$params) {
                        if ( $$valid_params{$param} ) {
                                $self->$param($val);
                        } else {
                                $self->push_errors("invalid parameter:" . $param . " = 
" . $val);
                                $error_in = 1;
                        }
        }
        # Check that required args are present.
        while (($param, $val) = each %$valid_params) {
                if( ! $self->$param() && $val eq RP_REQUIRED_ARG ) {
                        $self->error_errors("required parameter: " . $param . " is not 
set");
                        $error_in = 1;
                }
        }
        return $error_in;
}
sub run_command {
        # (command_path=>"command_path",command_args=>"command_args",$run_dir)
        my ($self, %args) = @_;
        my $ProcessObj;
        my $error_in = 0;
        my $ExitCode = 0;
        my $lineback;
        my %valid_params = (
                command_path => RP_REQUIRED_ARG,
                command_args => RP_REQUIRED_ARG,
                run_dir => RP_OPTIONAL_ARG,
        );
        $self->clear_command_path;
        $self->clear_command_args;
        $self->run_dir(".");    # Set the default directory to run in.
        # Check if args passed in are valid.
        $error_in = $self->check_params(\%valid_params, \%args );

        # Return if there are any errors in the input args.
        return 1 if ( $error_in );

        if ( -d $self->run_dir() ) {
                chdir $self->run_dir();
        } else {
                 $self->push_errors("Directory to run in does not exist, nothing 
done.");
                return 1;
        }

    #create a pipe in order to read the new process's stdout back
    pipe(PIPE_OUT_READ,PIPE_OUT_WRITE) || die "failed to create pipe";
    PIPE_OUT_WRITE->autoflush(1);

    #asign the pipe's write end to stdout
    open(PREV_STDOUT,">&STDOUT") || die "failed to save stdout";
    close(STDOUT)        || die "failed to close dupped stdout";
    open(STDOUT,">&PIPE_OUT_WRITE")  || die "failed to reasign stdout";
    close(PIPE_OUT_WRITE)      || die "failed to pipe write after use";

        $ExitCode = Win32::Process::Create($ProcessObj,
                $self->command_path(),
                $self->command_path() . " " . $self->command_args(),
                1,
                NORMAL_PRIORITY_CLASS,
                $self->run_dir()
        );
  #after child started (or not), restore the stdout
  open(STDOUT,">&PREV_STDOUT") || die "failed to restore stdout";
  close(PREV_STDOUT)      || die "failed to close the dupped stdout";
        if ( $ExitCode == 0 ) {
                $self->push_errors("Could not start process.");
                return 1
        }
        do {
                $lineback = <PIPE_OUT_READ>;
                if ( $self->perLineCheck($lineback) ) {
                        $self->push_errors("User selected Cancel, Aborting command");
                        $ProcessObj->Kill( 999 );
                        return 1;
                }
                $ProcessObj->GetExitCode( $ExitCode );
        } while($ExitCode == 259);
  if ( ! PIPE_OUT_READ->close ) {
                push_errors("failed to close pipe read after use");
                return 1;
        }
        return $ExitCode;
}

1;
###################Clip Here###################################
Here is a test program test_rp.pl
###################Clip Here###################################
use strict;
use run_process;
sub Main {
        my $run_dir = "c:/";
        my $command_path = 'c:/perl/bin/perl.exe';
        my $command_args = '-V';
        my $status;
        my @errors;

        my $rp = run_process->new();
        $rp->perlinecallback(sub {CheckLine(@_)});

        $status = $rp->run_command(
                "command_path" => $command_path,
                "command_args" => $command_args,
                "run_dir" => $run_dir,
        );
        print "status: " . $status . "\n";
        if ( $status ) {
                @errors = $rp->errors;
                foreach my $e ( @errors ) {
                        print $e . "\n";
                }
        }
}
sub CheckLine {
        my ($zipobj,$lineback) = @_;
        if ( $lineback ) {
                chomp $lineback;
                print "lineback: " . $lineback . "\n";
        }
        return 0;
}

Main();
###################Clip Here###################################

Eloy

~=====================================================================~
~[  Eloy A. Gonzales                     Voice: (505) 844-1063       ]~
~[  Sandia National Laboratories         Fax:   (505) 844-7059       ]~
~[  Org 05743 MS 0965                    email: [EMAIL PROTECTED]   ]~
~[  Albuquerque, New Mexico 87185-0965   pager: (505) 540-5700       ]~
~=====================================================================~



_______________________________________________
Perl-Win32-Users mailing list
[EMAIL PROTECTED]
http://listserv.ActiveState.com/mailman/listinfo/perl-win32-users

Reply via email to