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

Hi monks,

I was wondering if there is a way for me to catch the output of a script that I exec(). I've essentially got a daemon process that will fork off and exec() scripts, catches their termination signals and continues on its way. Is there any way, without modifying the scripts that are being exec()'d, that the daemon process can catch any output to STDOUT or STDERR that the fork/exec()'d scripts produce?

I've tried redirecting STDOUT/STDERR to a scalar within the child segment, prior to the exec call, but that information is lost when the child terminates (its copy of the variable is local to its branch of the fork, as I understand it).

Is there any way around this? Any advice is welcome.

Thanks

Replies are listed 'Best First'.
Re: Exec'ing and output
by sauoq (Abbot) on Oct 21, 2005 at 21:06 UTC

    It seems to me you might not really want to fork and exec... you might want to just fork. Then you can do anything you want in the child. From there, use IPC::Open3 or qx// (or open a pipe) with some redirection to get at both the stdout/stderr of the process. Use whatever method you want to hand the output back to the parent.

    -sauoq
    "My two cents aren't worth a dime.";
    
      Well, the only reason I want to exec is because what I want to do in the child is contained in (several) separate scripts, which the daemon won't 'know' about in advance.

      Also, I can't let the script just sit and wait for one script to finish before moving on to the next, as I may need to exec several scripts one after another, independently, and they could take some time to complete. So system()'ing them is out.

      This leads to another problem.. Is there any way that you can distinguish which process/scripts last wrote to STDOUT or STDERR if I reopen those filehandles to a temporary filehandle or a scalar as an above monk posted?

      Ideally, what I'd like to do is tell the children that are exec()'ing to call my logging function whenever their scripts print to STDOUT or STDERR. Is this even possible? I have a pretty specific logging format I need to conform to, and I'd like to be able to just call a function with the content of a print statement, and allow that function to handle formatting.

      Thanks again for all of your help.

        This leads to another problem.. Is there any way that you can distinguish which process/scripts last wrote to STDOUT or STDERR if I reopen those filehandles to a temporary filehandle or a scalar as an above monk posted?

        You can reopen them to a new filehandle for each invocation and keep all the active filehandles. Use select to see which have data ready to be read. (IO::Select might be an easier interface to deal with.)

        -sauoq
        "My two cents aren't worth a dime.";
        
Re: Exec'ing and output
by BUU (Prior) on Oct 21, 2005 at 20:59 UTC
    Reopen STDOUT and STDERR *before* you fork. Preferably to a new handle in your parent. The parent must then read from them.
Re: Exec'ing and output
by Roy Johnson (Monsignor) on Oct 21, 2005 at 21:33 UTC
    perldoc -f open and go down a long way to where it talks about doing things like
    open(FOO, '-|') || exec 'cat', '-n', $file;
    The calling script reads the STDOUT of the exec'd program via the FOO filehandle. You'd need to redirect STDERR to STDOUT if you want them both to go there.

    Caution: Contents may have been coded under pressure.
Re: Exec'ing and output
by ikegami (Patriarch) on Oct 22, 2005 at 01:03 UTC
    perlipc illustrates how to do this from scratch, and IPC::Run simplifies the process.