OfficeLinebacker has asked for the wisdom of the Perl Monks concerning the following question:

Greetings, esteemed monks!

I've been toying with different ways of capturing STDERR separately from STDOUT and doing a quick transformation of it, to give it "big","em",and "strong" elements to it for display of the whole output of a cron job.

You can see a node (my first question here as an Anonymous Monk) that got me started here: Prepending a string to STDERR output, and logging STDOUT & STDERR synchronously to a file

So one of my main questions is, is there any benefit to using scalars as arguments to open3()?

For example (my apologies for all the commented-out print statements),

my $cmdin=gensym; my $cmdout=gensym; my $cmderr=gensym; eval{ $pid = open3($cmdin, $cmdout, $cmderr, $cmd); #$val = waitpid(-1,0); }; die "Exception raised in block using open3: $@\n" if $@; $selector = IO::Select->new(); $selector->add($cmdout, $cmderr); #print "After selector->add\n"; while (@ready=$selector->can_read){ #print "In while loop\n"; foreach $fh (@ready) { #print "In foreach loop; fh is $$fh.\n"; my $byte; my @line; while ((sysread($fh, $byte, 1) == 1) && ($byte ne "\n")){push(@lin +e,$byte);}; #$line = scalar <$fh>; #print "line we just read in is $line"; if (@line){ my $line2=join("",@line); #added <strong> here JWC 5/9/06 #print "Printing $line to log:\n"; #print "printing $$fh output to log\n"; if (fileno($fh) == fileno($cmderr)) {print LOG "<em><strong><big +>STDERR: $line2</big></strong></em>\n";} else {print LOG "$line2\n";} #print "printed $$fh output to log\n"; } else{ #print "the line variable was empty--removing $$fh from selector +.\n"; $selector->remove($fh); #print "removed $$fh from selector\n"; } #print "at end of foreach loop.\n"; } #print "at end of while loop.\n"; } close($cmdout)|| warn "Error: Could not close $$cmdout: $!"; close($cmderr)|| warn "Error: Could not close $$cmderr: $!"; print LOG "*-*-end_run-*-*\n"; close(LOG);

vs.

$pid = open3(*CMD_IN, *CMD_OUT, *CMD_ERR, $cmd); close(CMD_IN); $SIG{CHLD} = sub { print "REAPER: status $? on $pid\n" if waitpid($pid, 0) > 0 }; $selector = IO::Select->new(); $selector->add(*CMD_ERR, *CMD_OUT); while (@ready = $selector->can_read) { foreach $fh (@ready) { $line = scalar <$fh>; if (fileno($fh) == fileno(CMD_ERR)) {print "STDERR: ", $line} else {print "STDOUT: ", $line} ($line) || $selector->remove($fh); } } close(CMD_OUT); close(CMD_ERR);
Now one thing I have head is to never mix synch and asych i/o, in other words the $selector-can_read uses select(), which uses asynch IO, I believe, but $line=scalar<$fh> uses synchronous? I dunno, I came up with a kloogy solution to that so I'd like to know also what's the best practice. I've had more luck with the first variation than the second, so far.

Note that a lot of the commented out part was stuff that I tried based on doing some searches on here about the behavior of open3().

A test script I've been using follows:

#!/opt/local/bin/perl $|++; print "1: I am great!\n"; print "2: I am great!\n"; warn "3: Warning: I am great!\n"; print "4: I am great!\n";
_________________________________________________________________________________

Without me, it's just aweso

Replies are listed 'Best First'.
Re: Best practice for sychronous output handling using open3()?
by stonecolddevin (Parson) on May 11, 2006 at 02:51 UTC
    with only skimming over the code, i wonder why you have three variables assigned to the same thing?
    my $cmdin=gensym; my $cmdout=gensym; my $cmderr=gensym;
    Why not just $cmdstuff = gensym?

    That said, it seems like this would be a job for something that's probably been written already. I know for sure there are a lot of cron scripts out there...have you looked on CPAN?

    meh.

      gensym (in Symbol) returns a ref to a new glob every time it's called.

      my $cmdin=gensym; my $cmdout=gensym; my $cmderr=gensym; open3($cmdin, $cmdout, $cmderr, $cmd);

      is like

      my $cmdin=gensym; my $cmdout=gensym; my $cmderr=gensym; open3(\*IN, \*OUT, \*ERR, $cmd);

      without the risk of conflicting names.

        my mistake. clearly i didn't do my research. downvote as needed.
        meh.
Re: Best practice for sychronous output handling using open3()?
by OfficeLinebacker (Chaplain) on May 11, 2006 at 16:52 UTC
    Greetings, esteemed monks!

    Thanks for the tips, all. I will have to go in and read the source for open3(). It turns out that the first approach (using sysreads) causes some processes not to finish, whereas I was not getting problems with the $line= scalar <$fh> thing. I only started messing with it because we have a particularly lengthy script, and the output wasn't showing up in the log even though the script had started. That may have had something to do with turning autoflush on in the called script though.

    _________________________________________________________________________________
    Without me, it's just aweso
Re: Best practice for sychronous output handling using open3()?
by jesuashok (Curate) on May 11, 2006 at 06:42 UTC
    Hi

    There is nothing mentioned about perl's synchronous open and asynchronous open. If you really want to know more about you can have the source code of IPC::open3 module. even they have not specified anything about synchronous open.

    "Keep pouring your ideas"