perl 什么是STDOUT类型,如何选择写入它?

pb3s4cty  于 2022-11-15  发布在  Perl
关注(0)|答案(3)|浏览(157)

STDOUT有“类型”吗?

printf STDERR ("STDOUT = %s\n", STDOUT);
printf STDERR ("\*STDOUT = %s\n", *STDOUT);
printf STDERR ("\\\*STDOUT = %s\n", \*STDOUT);

产生:

STDOUT = STDOUT
*STDOUT = *main::STDOUT
\*STDOUT = GLOB(0x600078848)

我理解*main::STDOUTGLOB(0x600078848)条目。“bareword”条目让我很好奇。
我这样问是因为我想把一个类似文件句柄的参数传递给一个方法调用。在'C'中,我会使用一个文件描述符或File *。我希望它默认为STDOUT。我所做的是:

$OUT_FILE_HANDLE = \*STDOUT;
if(@ARGV > 0 ) {
    open($OUT_FILE_HANDLE, ">", "$ARGV[0]") or die $!;
}

它可以工作,但我不知道我到底做了什么。我搞砸了STDOUT吗?我怀疑我“破坏”(覆盖)了STDOUT,这不是我想要的。
请原谅这个复合问题他们似乎有关系。

kkih6yb8

kkih6yb81#

创建一个词法文件句柄作为STDOUT的副本,并根据需要对其进行操作

sub manip_fh { 
    my ($fh) = @_;
    say $fh "hi";                              # goes to STDOUT
    open my $fh, '>', 'a_file.txt' or die $!;  # now it's to a file
    say $fh "hello";
}

open my $fh, '>&', STDOUT;  # via dup2

manip_fh($fh);

say "hi";  # still goes where STDOUT went before being dup-ed (terminal)

这个新的、独立的文件句柄可以重新打开给另一个资源,而不影响STDOUT。请参阅open
问题中的$OUT_FILE_HANDLE = \*STDOUT;创建了一个别名,因此当“新的”别名发生变化时,STDOUT确实会发生变化。

our $NEW = \*STDOUT;  # "our" only for checks here, otherwise better "my"
say *{$main::NEW};    #--> *main::STDOUT

或者通过打印符号表中的IO槽来

say for *{$main::NEW}{IO}, *{$main::{STDOUT}}{IO};

并且看到(对象串化为)相同(例如IO::File=IO(0x1a8ca50))。
当像第一个代码片段那样使用open和模式>&复制它时(但是作为全局our),它输出*main::NEW,并且它的IO::File对象与STDOUT的对象不同。(使它成为全局our,这样它就在这些检查的符号表中,而不是在真实的使用中;拥有一个my要好得多。)

ldioqlga

ldioqlga2#

来自perlvar:
以数字或标点符号字符开始的Perl标识符不受package声明的影响,并且总是被强制放在包main中;它们也免除了strict 'vars'错误。一些其他名称也以下列方式免除:【......】STDOUT
因此,STDOUT是一个包含预打开文件句柄的全局变量。
从perlfunc:
如果FILEHANDLE是一个未定义的标量变量(或者数组或散列元素),则会自动激活一个新的文件句柄,这意味着会为该变量分配一个对新分配的匿名文件句柄的引用。否则,如果FILEHANDLE是一个表达式,则其值为真实的的文件句柄。
你的$OUT_FILE_HANDLE不是未定义的,所以它的值STDOUT是被打开的。AFAIK,如果你打开一个已经打开的句柄,它会先被隐式关闭。
有几种方法可以做到这一点。第一种方法从上面的引用中显而易见--不要在open之前定义$OUT_FILE_HANDLE

if (@ARGV > 0 ) {
  open($OUT_FILE_HANDLE, ">", "$ARGV[0]") or die $!;
} else {
  $OUT_FILE_HANDLE = \*STDOUT;
}
# do stuff to $OUT_FILE_HANDLE

另一种是使用select,这样就不需要传递文件句柄:

if (@ARGV > 0 ) {
  open($OUT_FILE_HANDLE, ">", "$ARGV[0]") or die $!;
  select $OUT_FILE_HANDLE;
}
# do stuff (without specifying a file handle)
select STDOUT;
lo8azlld

lo8azlld3#

您的问题的这一部分没有得到回答:

  • “裸词”让我很好奇 *

一个没有其他含义的标识符是一个字符串文字,它产生自己。[1]例如,foo'foo'相同。

$ perl -e'my $x = foo; print "$x\n";'
foo

这很容易出错,因此我们使用use strict qw( subs );来防止这种情况。

$ perl -e'use strict; my $x = foo; print "$x\n";'
Bareword "foo" not allowed while "strict subs" in use at -e line 1.
Execution of -e aborted due to compilation errors.

1.请参阅this以了解Perl可以指定的其他含义。

相关问题