Beefy Boxes and Bandwidth Generously Provided by pair Networks
Syntactic Confectionery Delight
 
PerlMonks  

Comment on

( #3333=superdoc: print w/ replies, xml ) Need Help??

While there's much that could be cleaned up, and in spite of my initial gut feeling in Open3 and bad gut feeling, This open 3 module has provided me what you seek in several large enterprise applications without any problems.

Here's the code as it's been running in production without change for the last 4 years

package OSify::Execute; =head1 NAME C<OSify::Execute> -- Provides Access to the system Shell =head1 SYNOPSIS C<B<use OSify::Execute;>> =head1 DESCRIPTION Purpose: Provide a consistent reusable loged common Perl command interface to any supported system shell. Currently only supports solar +is and MSwin32 ( see L<C<OSify::OSify>|OSify> ). =cut use diagnostics; use strict; ###################################################################### +######## # # # This Module is the bottom line in package OSify:: This is where the + # # duct tape directly acceses the OS. Consequently, for purposes of sec +urity # # and extensibility with other Teams || Departments, this code and in + # # particular this module, are heavily annotated. (More notes than code +) # # # # Needs: Currently lacks a security wrapper. This module at times has +an # # effective ID of root. A package OSify::SecurityAPI (LDAP?) should be + # # pursued whenever possible. See Notes with each function as to short + and # # longterm improvements. # # # ###################################################################### +######## # Standard Perl libraries use IPC::Open3; # for OSexecute use IO::Handle '_IOFBF'; # for OSexecute use IO::Handle '_IOLBF'; use IO::Select; # This module currently requires the following functions use Exporter(); our @EXPORT = qw[ ]; our @EXPORTOK = qw[ OSrun ]; =pod =head2 C<B<OSrun()>> Forks a process into the OS via C<OSify::Execute::OSexecute()> It returns the pid, stdout and stderr in a hash, logging the execution to the specified logfile. Intended as the common interface to the execution of the command. This is the only exported function which somewhat forces commands requesting execution to be 'wrapped'. Currently it acts as an optional wrapper to the logger but future functionality ( LDAP? ) should be integrated either here or in a similiar module. Any Calling program must handle the C<STDERR> to determine if it worke +d or not. =over 4 =item usage: C<%result = B<OSexec("OSrun", "logfile");>> C<%result = ( stdout =E<gt> $stdout, stderr =E<gt> $stderr pid =E<gt> +$pid );> =back =cut ###################################################################### +######## # Potential problem. Learning how to either disable or take advantage # of Perl's Filehandle buffering. While the latter would provide # obvious performance benifits. Could run into problems with the # writing to the logfile writing otherwise. ( Refer: Suffering from # Buffering http://perl.plover.com/FAQs/Buffering.html ) sub OSrun { my $execute = $_[0]; my $logfile = $_[1]; my $silent = 0; if ( $_[2] ) { $silent = $_[2]; } # See if execution would be too large for the input # buffer. If so Create and execute a script instead. my @execute; @execute = split /\s/, $execute; # Interface the logger if ( $logfile && $silent ) { if ( $silent > 0 ) { OSify::OSify::OSlogger( $logfile, "Executing $execute", 1 +); } } # Send the command to the executioner my %OSreturn; %OSreturn = OSexecute( @execute ); # Return the output return %OSreturn; } =pod =head2 B<C<OSexecute()>> Forks a process into the OS returning the pid, stdout and stderr in a +hash. Intended to be strictly the minimum required functionality to execute +a command and return all of its relevant information. =over 4 =item usage: C<%result = B<OSexecute("Commandline");>> C<%result = ( stdout =E<gt> $stdout, stderr =E<gt> $stderr pid =E<gt> +$pid );> =back =cut # $@ should NEVER report errors! Termination (die) is written as manda +ntory. sub OSexecute { my @execute = @_; my $stdin = IO::Select->new(); $stdin->add("\*STDIN"); my $din = IO::Handle->new(); $din->autoflush(1); $stdin->add($din); my $stdout = IO::Select->new(); $stdout->add(\*STDOUT); my $dout = IO::Handle->new(); $dout->autoflush(1); $stdout->add($dout); my $stderr = IO::Select->new(); $stderr->add(\*STDERR); my $derr = IO::Handle->new(); $derr->autoflush(1); $stderr->add($derr); OSify::PerlFunc::debug("Executing @execute\n", 10 ); my $pid = 1; # Here is the actual execution my $val = -1; # This eval is looped to allow for retries when intermitant # Resouce temporarily unavailable problems occur. my ($i, $retry, $napTime); $napTime = 5; $retry = 3; for ( $i=1; $i<=$retry; $i++ ) { eval { $pid = open3( $din, $dout, $derr, @execute ); while ( $val != -1 ) { # waitpid waits for the proces to exit # $val could be used as a means to determine status # while waiting if that functionality becomes needed. $val = waitpid(-1,0); #wait's for process to comple +te } }; if ( $@ && $i > $retry ) { die "OSify::OSexecute died upon execution of\n@execute\nWi +th $@"; } elsif ( $@ =~ /Resource temporarily unavailable/i ) { OSify::PerlFunc::debug("Failed to execute\n@execute\non at +tempt number $i\nResource temporarily unavailable.\n Retrying in $nap +Time secs\n", 100); undef($@); sleep($napTime); } elsif ( ! $@ ) { $i = $retry; undef($@); } } # Gather the results my $line; # Standard Out my @stdout = <$dout>; my $out; foreach $line (@stdout) { OSify::PerlFunc::debug( "@execute STDOUT processing \$line = $ +line", 10); $line = OSify::PerlFunc::trimSpaces($line); $out = $out . $line . "\n"; } if ( ! $out ) { $out = 1; } # Standard Error my @stderr = <$derr>; my $err; foreach $line ( @stderr ) { OSify::PerlFunc::debug( "@execute STDERR processing \$line = $ +line", 10); $line = OSify::PerlFunc::trimSpaces($line); $err = $err . $line . "\n"; } if ( ! $err ) { $err = 1; } # Flush and close the Filehandles $din->flush(); $din->close; $dout->flush(); $dout->close; $derr->flush(); $derr->close; undef $stdin; undef $stdout; undef $stderr; my %OSexec = ( stdout => $out, stderr => $err, pid => $pid, ); return %OSexec; } 1; =pod =head1 REQUIRES Standard Perl Modules: L<C<IPC::Open3>|Open3>, L<C<IO::Handle>|Handle>, L<C<IO::Select>|selec +t> OSify Modules: L<C<OSify::PerlFunc>|PerlFunc>, L<C<OSify::OSify>|OSify> =head1 Author =head1 See Also L<C<OSify::OSify>|OSify>, L<C<OSify::FileFunc>|FileFunc>, L<C<OSify::PerlFunc>|PerlFunc>, L<C<OSify::Ultimail>|Ultimail> =head1 =cut =cut

Edited by planetscape - added readmore tags

( keep:0 edit:11 reap:0 )


In reply to Re: Synchronizing STDERR and STDOUT by coreolyn
in thread Synchronizing STDERR and STDOUT by Ovid

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!
  • 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, 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, sup, table, tbody, td, tfoot, th, thead, tr, tt, u, ul, wbr
  • Outside of code tags, you may need to use entities for some characters:
            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.
  • Log In?
    Username:
    Password:

    What's my password?
    Create A New User
    Chatterbox?
    and the web crawler heard nothing...

    How do I use this? | Other CB clients
    Other Users?
    Others exploiting the Monastery: (11)
    As of 2014-10-30 23:06 GMT
    Sections?
    Information?
    Find Nodes?
    Leftovers?
      Voting Booth?

      For retirement, I am banking on:










      Results (211 votes), past polls