17

我有一个 Perl 脚本,它自己分叉和守护进程。它由 cron 运行,所以为了不留下僵尸,我关闭了 STDIN、STDOUT 和 STDERR:

open STDIN, '/dev/null'   or die "Can't read /dev/null: $!";
open STDOUT, '>>/dev/null' or die "Can't write to /dev/null: $!";
open STDERR, '>>/dev/null' or die "Can't write to /dev/null: $!";
if (!fork()) {
  do_some_fork_stuff();
  }

我的问题是:我想在此之后至少恢复 STDOUT(恢复其他 2 会很好)。但是我需要使用什么魔法符号来重新打开 STDOUT,就像以前的 STDOUT 一样?

我知道如果我从 tty 运行,我可以使用“/dev/tty”(但我是从 cron 运行并取决于其他地方的标准输出)。我还阅读了可以将 STDOUT 放在一边的技巧open SAVEOUT,">&STDOUT",但是仅制作此副本的行为并不能解决留下僵尸的原始问题。

我正在寻找是否有一些魔法open STDOUT,"|-"(我知道不是)以应该打开的方式打开 STDOUT。

4

3 回答 3

15

# 文件描述符的副本

open(CPERR, ">&STDERR");

# 将标准错误重定向到警告文件

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

# 关闭重定向的文件句柄

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

# 恢复标准输出和标准错误

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

#我希望这对你有用。

#-哈里帕萨德 AJ

于 2009-11-12T07:49:51.487 回答
5

如果它仍然有用,那么会想到两件事:

  1. 您可以仅在子进程中关闭 STDOUT/STDERR/STDIN(即 if (!fork())。这将允许父进程仍然使用它们,因为它们仍然会在那里打开。

  2. 我认为您可以使用更简单的 close(STDOUT) 而不是将其打开到 /dev/null。

例如:

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();
}
于 2009-08-29T01:08:53.103 回答
4

一旦关闭,就无法恢复。

为什么又需要 STDOUT?将消息写入控制台?为此使用 /dev/console,或使用 Sys::Syslog 写入 syslog。

老实说,另一个答案是正确的。如果您想稍后重新打开它,您必须保存旧的标准输出(克隆到新的 fd)。它确实解决了“僵尸”问题,因为您可以将 fd 0(和 1 和 2)重定向到 /dev/null。

于 2009-08-28T19:43:01.187 回答