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

What type is STDOUT, and how do I optionally write to it?

STDOUT 有 "type" 吗?

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' 中,我会使用文件描述符或文件 *.我希望它默认为 STDOUT。我所做的是:

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

它有效,但我不确切知道我做了什么。我搞砸了标准输出吗?我怀疑我有 "ruined"(覆盖)STDOUT,这不是我想要的。

复合题请见谅;他们似乎有关联。

来自 perlvar:

Perl identifiers that begin with digits or punctuation characters are exempt from the effects of the package declaration and are always forced to be in package main; they are also exempt from strict 'vars' errors. A few other names are also exempt in these ways: [...] STDOUT

因此,STDOUT 是一个包含 pre-opened 文件句柄的全局变量。

来自 perlfunc:

If FILEHANDLE is an undefined scalar variable (or array or hash element), a new filehandle is autovivified, meaning that the variable is assigned a reference to a newly allocated anonymous filehandle. Otherwise if FILEHANDLE is an expression, its value is the real filehandle.

您的 $OUT_FILE_HANDLE 不是未定义的,因此正在打开的是它的值 STDOUT。据我所知,如果您打开一个已经打开的句柄,它会先隐式关闭。

有多种方法可以满足您的需求。第一个从上面的引用中显而易见——不要在 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;

创建一个词法文件句柄作为 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 确实在“新”更改时发生了更改。你可以通过打印 typeglob

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

或者通过为两个

打印符号 table 中的 IO
say for *{$main::NEW}{IO}, *{$main::{STDOUT}}{IO};

看到(对象字符串化为)相同(例如 IO::File=IO(0x1a8ca50))。

当它像第一个代码片段(但作为全局 our)一样使用 open 和模式 >& 被欺骗时,它会打印 *main::NEW,其 IO::File 对象与 STDOUT 不同。 (将其设置为全局 our 以便它在这些检查的符号 table 中,但不是实际使用;much 更好 my.)

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

The "bareword" one leaves me curious.

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

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

这是 error-prone,所以我们使用 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. 有关 Perl 可以指定的其他含义,请参阅