将文件句柄变量从STDOUT重新分配给没有undef()的文件时,Perl的奇怪行为
执行以下简化代码时:
use strict; # [01]
use warnings FATAL => 'unopened'; # [02]
# [03]
my ($inHandle, $outHandle) = (*STDIN, *STDOUT); # [04]
print $outHandle "STDOUT 1n"; # [05]
# [06]
# $outHandle re-assigned to outputA.txt ??? # [07]
open($outHandle, ">outputA.txt") or die ("A: $!n"); # [08]
print $outHandle "FILE An"; # [09]
print "STDOUT? 2n"; # [10]
print STDOUT "STDOUT 3n"; # [11]
close $outHandle; # [12]
# [13]
# $outHandle is closed # [14]
print STDOUT "STDOUT 4n"; # [15]
print "STDOUT? 5n"; # [16]
print $outHandle "FILE CLOSEDn"; # [17]
# [18]
# $outHandle re-assigned to outputA.txt ??? # [19]
open($outHandle, ">outputB.txt") or die ("B: $!n"); # [20]
print $outHandle "FILE Bn"; # [21]
close $outHandle; # [22]
我遇到以下奇怪的行为:
- 打印(第 [18] 行)到关闭(未打开)
$outputHandle(第 [13] 行)时,即使use warnings FATAL => 'unopened';使用,也不会发出警告。 - 输出如下,这不是我所期望的。
| 标准输出 | 输出A.txt | 输出B.txt |
|---|---|---|
| 标准输出 1 | 文件A | 文件乙 |
| 标准输出?2 | ||
| 标准输出 3 |
回答
当标准输出流†被重定向(重新打开)到一个文件时,就无法用它打印到控制台;本来要去那里的内容现在已连接到该文件。所以一旦完成,所有其他打印到STDOUT,以一种或另一种方式完成,结束在文件中。
然后那个文件句柄被关闭;之后就不能再打印STDOUT了。‡
所以第一个表是人们应该期待的。
打印到未打开的文件句柄时,我确实收到警告,因此对于STDOUT关闭后的任何和所有打印。 编辑...没有FATAL => 'unopened'但正常warnings启用,即(我如何测试此答案)。但是,仅使用该警告类别,就没有打印到已关闭文件句柄(已初始化然后关闭的文件句柄)的警告。请参阅此页面。
一些注意事项:
-
文档中的几页要学习:open , and
Playing with STDIN and STDOUT (old perlopentut) , and
open FILEHANDLE in perlfunc -
有一些方法可以通过控制来操作标准流。一种是“ dup ”(复制)它,以便在它被重定向、使用和关闭后可以恢复它。想到的一些例子:在关于 STDOUT和关于重定向的帖子中。(请注意,这
$fh = *STDOUT会创建一个别名,因此当其中一个更改时,另一个也会更改。)或者,在一个单独的范围内(块会做得很好),这样做
local *STDOUT;之后所有提到的STDOUT都将与这个本地副本一起工作。一旦离开范围,全局范围就会恢复。或者您可以使用
select而不是弄乱STDOUT本身。其中大部分都在perl.com 文章中得到了很好的总结。有关更多信息,请参阅此页面
-
“三个论点”
open更好:(open my $fh, '<', $file ...并检查or die $!) -
它被称为“句柄”,而不是“句柄”
† 该文件描述符1,为此,Perl提供一个打开STDOUT的文件句柄(真*STDOUT glob的,但是*当一个文件句柄,预计可以被省略,或作为一个适当的参考*STDOUT)
‡即使STDOUT没有首先被重定向,一旦它关闭,就没有与标准输出流的连接,也没有像以前那样重新打开它的简单方法。(当然有办法把东西放在终端上。)
一般来说,关闭STDOUT不是一个好主意,因为很多人都希望它是开放的。一方面,一旦 fd1 被腾空,其他东西可能会被分配,带来奇怪的麻烦(参见这篇文章和Perl bug #23838)。如果您的程序分叉(以某种方式),并且子进程继承了他们不可能期望的东西怎么办?可能在下一行调用的库怎么办?等等。
有更好的方法来操作STDOUT,在文本中提到和链接。
如果您需要 STDOUT离开,至少将其重定向到/dev/null(nul在 Windows 上)而不是完全关闭它。