+3  A: 

Once closed, there's no way to get it back.

Why do you need STDOUT again? To write messages to the console? Use /dev/console for that, or write to syslog with Sys::Syslog.

Honestly though, the other answer is correct. You must save the old stdout (cloned to a new fd) if you want to reopen it later. It does solve the "zombie" problem, since you can then redirect fd 0 (and 1 & 2) to /dev/null.

jmanning2k
Playing around with things, I found that if I used the "SAVEOUT" method, cron would still be waiting.I need stdout again because the script launched by cron already has an output redirect, and I was trying to make minimal changes to it beyond the zombie fix.I did find another solution that works for me though:If I replace do_some_fork_stuff() with a system call to another "wrapper" script, and _that_ script just forks itself and does the fork_stuff(), then I can both detach from cron properly and preserve stdout for the remainder of the main script. (Hopefully that description makes sense)
Josh
Yikes. Complicated, but if it works... Try exec in the cronjob line to fix cron waiting for your process. Had that in a draft, but must have cut it before posting.
jmanning2k
Aha! "exec" seems to be exactly what I originally wanted! That's perfect! No changes to the code, at least for my scaled-down test. Will have to test it in the office tomorrow. Thanks!
Josh
sadly, after trying it (tomorrow meant Monday), "exec" still leaves a zombie around, just lower down the chain.
Josh
+2  A: 

If it's still useful, two things come to mind:

  1. You can close STDOUT/STDERR/STDIN in just the child process (i.e. if (!fork()). This will allow the parent to still use them, because they'll still be open there.

  2. I think you can use the simpler close(STDOUT) instead of opening it to /dev/null.

For example:

if (!fork()) {
    close(STDIN) or die "Can't close STDIN: $!\n";
    close(STDOUT) or die "Can't close STDOUT: $!\n";
    close(STDERR) or die "Can't close STDERR: $!\n";
    do_some_fork_stuff();
}
Michael Krebs
The problem with closing STDOUT instead of reopening is that if you open other files, they might get fd 0,1 or 2 - preventing you from reopening STDOUT in the future.
jmanning2k
+4  A: 

# copy of the file descriptors

open(CPERR, ">&STDERR");

# redirect stderr in to warning file

open(STDERR, ">>xyz.log") || die "Error stderr: $!";

# close the redirected filehandles

close(STDERR) || die "Can't close STDERR: $!";

# restore stdout and stderr

open(STDERR, ">&CPERR") || die "Can't restore stderr: $!";

#I hope this works for you.

#-Hariprasad AJ

Hari