perl - 将文件句柄变量从 STDOUT 重新分配给没有 undef() 的文件时 Perl 的奇怪行为
问题描述
执行以下简化代码时:
use strict; # [01]
use warnings FATAL => 'unopened'; # [02]
# [03]
my ($inHandle, $outHandle) = (\*STDIN, \*STDOUT); # [04]
print $outHandle "STDOUT 1\n"; # [05]
# [06]
# $outHandle re-assigned to outputA.txt ??? # [07]
open($outHandle, ">outputA.txt") or die ("A: $!\n"); # [08]
print $outHandle "FILE A\n"; # [09]
print "STDOUT? 2\n"; # [10]
print STDOUT "STDOUT 3\n"; # [11]
close $outHandle; # [12]
# [13]
# $outHandle is closed # [14]
print STDOUT "STDOUT 4\n"; # [15]
print "STDOUT? 5\n"; # [16]
print $outHandle "FILE CLOSED\n"; # [17]
# [18]
# $outHandle re-assigned to outputA.txt ??? # [19]
open($outHandle, ">outputB.txt") or die ("B: $!\n"); # [20]
print $outHandle "FILE B\n"; # [21]
close $outHandle; # [22]
我遇到以下奇怪的行为:
- 打印(第 [18] 行)到已关闭(未打开)
$outputHandle
(第 [13] 行)时,即使use warnings FATAL => 'unopened';
使用时也不会发出警告。 - 输出如下,这不是我所期望的。
标准输出 | 输出A.txt | 输出B.txt |
---|---|---|
标准输出 1 | 档案一 | 文件 B |
标准输出?2 | ||
标准输出 3 |
这是我期望的输出,假设第 [17] 行被注释掉并且没有引发warnings FATAL => 'unopened'
标准输出 | 输出A.txt | 输出B.txt |
---|---|---|
标准输出 1 | 档案一 | 文件 B |
标准输出?2 | ||
标准输出 3 | ||
标准输出 4 | ||
标准输出?5 |
作为旁注:
- 原始程序默认输出到 STDOUT,但如果有参数传递给程序,则切换到输出到文件。
- 我正在使用“这是为 MSWin32-x64-multi-thread 构建的 perl 5,版本 28,subversion 1 (v5.28.1)”
解决方案
当标准输出流†</sup> 被重定向(重新打开)到文件时,就无法使用它打印到控制台;本来应该去那里的东西现在已连接到该文件。因此,一旦完成,所有其他打印到STDOUT
,以一种或另一种方式完成,都会在文件中结束。
然后那个文件句柄被关闭;之后就不能再打印STDOUT
了。‡</sup>
所以第一张桌子是人们应该期待的。
打印到未打开的文件句柄时,我确实收到警告,因此对于STDOUT
关闭后的任何和所有打印。 编辑...没有FATAL => 'unopened'
但正常warnings
启用,即(我如何测试这个答案)。但是,仅使用该警告类别,就没有打印到关闭的文件句柄(已初始化然后关闭的文件句柄)的警告。请参阅此页面。
一些注意事项:
需要研究的文档中的几页:open和 Playing with STDIN and STDOUT (old perlpentut),并 在 perlfunc 中打开 FILEHANDLE
有一些方法可以通过控制来操作标准流。一种是“复制”(复制)它,所以在它被重定向、使用和关闭之后,可以恢复它。想到的一些例子:在STDOUT和重定向的帖子中。(请注意,这
$fh = \*STDOUT
会创建一个别名,因此当其中一个更改时,另一个也会更改。)或者,在一个单独的范围内(块会很好),
local *STDOUT;
然后所有提及的内容STDOUT
都将与这个本地副本一起使用。一旦您离开范围,全局范围就会恢复。或者你可以使用
select
而不是搞乱STDOUT
本身。其中大部分都在perl.com 文章中得到了很好的总结。有关更多信息,请参阅此页面
“三个参数”
open
更好:(open my $fh, '<', $file ...
和检查or die $!
)它被称为“句柄”,而不是“处理程序”
†</sup>文件描述符 1,Perl 为其提供打开的STDOUT
文件句柄(实际上是*STDOUT
glob,但*
在需要文件句柄时可以省略,或者作为适当的参考\*STDOUT
)
‡</sup> 即使STDOUT
没有第一次重定向,一旦它关闭,就没有与标准输出流的连接,也没有简单的方法可以像以前一样重新打开它。(当然有办法把东西放在终端上。)
一般来说,关闭STDOUT
不是一个好主意,因为许多各方都希望它是开放的。一方面,一旦 fd1 被腾出,其他东西可能会被分配,但会有奇怪的麻烦(参见这篇文章和Perl bug #23838)。如果您的程序分叉(以某种方式),并且子进程继承了他们不可能期望的东西怎么办?可能在下一行调用的库是什么?等等。
有更好的方法来操作STDOUT
,在文本中提到和链接。
如果您需要 STDOUT
离开,至少将其重定向到/dev/null
(nul
在 Windows 上)而不是直接关闭它。
推荐阅读
- c++ - c++解构函数返回值
- python - 如何解决 ModuleNotFoundError: No module named 'flask_mysqldb' 在 Vs.Code 中的错误?
- python-2.7 - python中的分位数回归
- java - 计算 recyclerView 中选中的复选框
- spring - 每天午夜的春季调度程序 cron 表达式
- nlp - NLP 人工生成的字幕
- python - 如何将条形图标签移动到 Y 轴?
- python - 屏幕未使用海龟库中的 .update() 进行更新
- verilog - 如何使用触发器输出作为复位信号的输入
- mule - 使用 DWL 2.0 进行转换