2011-06-09 75 views
24

我想制作一个快速脚本,如果给出文件,则写入文件,如果没有给出文件,则写入stdout。如果我可以通过将一个新的文件句柄OUTFILE指向适当的文件句柄来启动脚本,那么我会更容易做到这一点。如何在Perl中将文件句柄指向STDOUT(或另一个文件句柄)?

我知道我可以通过在适当的时候将STDOUT指向我的输出文件来完成我想要的操作,但是我宁愿不这样做,因为我不想再混淆以后使用脚本的任何人,并想知道为什么他们的打印语句不工作。另外,我仍然希望自己偶尔使用打印语句来进行故障排除,并且不希望将此打印输出到输出文件。

的这一切说,我要找的是沿着线的东西:
open(OUTFILE, ($output ? ">$output" : STDOUT);
除了不起作用。

想法?

回答

37

一些方法(水珠):

# Requires 2-arg open, unfortunately 
open(OUTPUT, "> ".($output || '-')) or die; 

if ($output) { 
    open(OUTPUT, '>', $output) or die; 
} else { 
    *OUTPUT = *STDOUT; 
} 

if ($output) { 
    open(OUTPUT, '>', $output) or die; 
} else { 
    open(OUTPUT, '>&', \*STDOUT) or die; 
} 

一些方法(词汇VAR):

# Requires 2-arg open, unfortunately 
open(my $fh, "> ".($output || '-')) or die; 

my $fh; 
if ($output) { 
    open($fh, '>', $output) or die; 
} else { 
    $fh = \*STDOUT; 
} 

my $fh; 
if ($output) { 
    open($fh, '>', $output) or die; 
} else { 
    open($fh, '>&', \*STDOUT) or die; 
} 

一些方法(其他):

# Changes the default handle for <print "foo">. 
if ($output) { 
    open(OUTPUT, '>', $output) or die; 
    select(OUTPUT); 
} 
+2

'...} else {open($ fh,'>&'。fileno(STDOUT)); }' – mob 2011-06-09 19:59:30

3

您可以随时将常规输出写入STDOUT,并将您的调试语句写入STDERR。然后,如果用户想要输出到文件,他们可以将STDOUT重定向到命令行上的文件。

+0

就像我说的,我知道我可以重定向文件STDOUT,但是这真是我宁愿避免这样做的当其他人这样做时,我发现它令人困惑和烦人,并且以后我必须处理代码。它将作为最后的努力工作,但我宁愿只是将一个不同的文件句柄指向输出文件或标准输出,因为我认为这会更清晰。 – Eli 2011-06-09 17:08:22

+3

@Eli - 您不必在代码中执行此操作。只需编写脚本以便始终打印到STDOUT。当用户正常运行脚本时,他们会在屏幕上看到输出。但是他们也可以执行'scriptname.pl> filename.txt',在这种情况下,脚本将运行并且输出将以文件'filename.txt'结尾。 STDERR上的任何调试代码仍将出现在控制台上。这是大多数* nix实用程序和脚本工作的方式。 – 2011-06-09 17:17:34

+3

@Eli - 这是最简单的方法。您的脚本中没有任何知道不同输出路径的代码。您在代码中执行的所有操作都是写入STDOUT。用户决定他们何时使用脚本来查看控制台中的输出,还是将其输入到文件中,或者将其输入到另一个命令的STDIN中。 – 2011-06-09 17:21:06

4

没关系。弄清楚了。以“&”号投掷就是个诀窍。完整的工作代码是:
open(OUTPUT, ($output ? ">$output" : ">&STDOUT"));

+3

什么会使这个答案很好是解释这是如何工作的。 – Ether 2011-06-10 03:08:27

7

-是神奇的。按照惯例,或者你违反最小惊喜的原则。

use autodie qw(:all); 
use Getopt::Long qw(GetOptions); 
GetOptions(\my %opt, 'out=s') or die 'usage'; 
die 'usage' unless $opt{out}; 
open my $handle, ">$opt{out}"; 

perl foo -o blahblah  # opens file blahblah for writing 
perl foo -o -    # goes to STDOUT 

相关:Are there reasons to ever use the two-argument form of open(...) in Perl?

10

为了读者的缘故(因为OP已经 “得到它的工作”):

Perl文档, “perlopentut”(参阅perldoc perlopentut)给出了打开一个指向STDOUT的替代文件句柄的例子,但它使用裸字文件句柄和两个arg版本的open,这两个版本都有些古老。达米安康威的书“Perl最佳实践”(以及基于达米安书的Perl :: Critic)强调使用三个arg打开和词法文件句柄(my $foo样式文件句柄)。 chromatic的“Modern Perl”也简单地提到了使用词法文件句柄,并且在实际情况下劝阻裸字。三个参数open被认为是一种更安全的形式,因为它限制了壳注射的暴露。虽然这里的具体情况是低风险,但默认为三参数open仍然是一个好习惯。

它需要Perl的open文件中所示(参阅perldoc -f打开)的例子仔细阅读,和一点点解释注意到在使用时,打开一个重复filahandle指向STDOUT三ARG&符号的正确位置版本为open。有人可能会错误地认为这应该起作用:open my $fh, '>', '&STDOUT' or die $!;,主要是因为它看起来像我们以前看到的格式(符号名称前的符号)。但是这种语法并不是open需要的,我们习惯在完全不同的上下文中看到它:某些子程序调用。

打开一个傻瓜来STDOUT与三个ARG open正确的方法是将>&到相同的第二个参数结合起来,并留下STDOUT光秃秃的,就像这样:

use Modern::Perl; 

open my $fh, '>&', STDOUT or die "Bleah: $!"; 

say $fh 'Printing alternate filehandle "$fh" worked.'; 
say 'Implicitly printing to "STDOUT" also works.'; 

或者通过STDOUTopen作为对类型团的引用:

open my $fh, '>&', \*STDOUT or ...