如果STDOUT是另一个目的地,如何打印到STDERR?

时间:2013-03-14 18:30:29

标签: perl unix io stdout stderr

我希望Perl仅在STDOUT不相同的情况下写入STDERR。例如,如果STDOUT和STDERR都将输出重定向到终端,那么我不希望打印STDERR。

考虑以下示例(outerr.pl):

#!/usr/bin/perl

use strict;
use warnings;

print STDOUT "Hello standard output!\n";
print STDERR "Hello standard error\n" if ($someMagicalFlag);
exit 0

现在考虑一下(这是我想要实现的目标):

bash $ outerr.pl
Hello standard output!

但是,如果我重定向到文件,我想得到:

bash $ outerr.pl > /dev/null
Hello standard error

和反过来相似:

bash $ outerr.pl 2> /dev/null
Hello standard output!

如果我将两个/ err重定向到相同的文件,则只显示out:

bash $ outerr.pl > foo.txt 2>&1
bash $ cat foo.txt
Hello standard output!

那么有没有办法评估/确定OUT和ERR是否指向相同的“事物”(描述符?)?

2 个答案:

答案 0 :(得分:6)

在Unix风格的系统上,您应该能够:

my @stat_err = stat STDERR;
my @stat_out = stat STDOUT;

my $stderr_is_not_stdout = (($stat_err[0] != $stat_out[0]) ||
                            ($stat_err[1] != $stat_out[1]));

但是这不适用于Windows,它没有真正的inode数字。它既给出了误报(认为它们不同时也是不同的)和假否定(认为它们不相同时就​​是相同的。)

答案 1 :(得分:4)

你可以(差不多)用-t:

来做到这一点
-t STDERR
如果它是终端,则

将为true,对于STDOUT也是如此。

这仍然不会告诉你什么终端,如果你重定向到同一个文件,你可能仍然可以得到这两个。

因此,如果

-t STDERR && ! (-t STDOUT) || -t STDOUT && !(-t STDERR)

或更短

-t STDOUT ^ -t STDERR  # thanks to @mob

你知道你没事。

编辑:STDERR和STDOUT都是常规文件的解决方案:

汤姆克里斯蒂安森建议统计并比较dev和ino字段。这将在UNIX中工作,但正如@cjm指出的那样,而不是在Windows中。

如果您可以保证没有其他程序会写入该文件,您可以在Windows和UNIX中执行以下操作:

  1. 检查STDOUT和STDERR的文件描述符的位置是否为if 它们不相等,你用>>将其中一个重定向到a 非空文件。
  2. 否则,将42个字节写入文件描述符2
  3. 寻找文件描述符1的末尾。如果它比以前多42,则两者都被重定向到同一文件的可能性很高。如果不变,则文件不同。如果它被更改,但不是42,其他人在那里写,所有的赌注都关闭(但是,你不在Windows中,所以stat方法会起作用)。