select FILEHANDLE
select

返回当前选定的文件句柄。如果提供了 FILEHANDLE,则为输出设置新的当前默认文件句柄。这有两个效果:首先,没有文件句柄的writeprintsay默认为此 FILEHANDLE。其次,与输出相关的变量引用将引用此输出通道。

例如,要为多个输出通道设置表单顶部的格式,可以执行以下操作

select(REPORT1);
$^ = 'report1_top';
select(REPORT2);
$^ = 'report2_top';

FILEHANDLE 可以是一个表达式的值,该表达式给出实际文件句柄的名称。因此

my $oldfh = select(STDERR); $| = 1; select($oldfh);

一些程序员可能更愿意将文件句柄视为具有方法的对象,更愿意将最后一个示例写成

STDERR->autoflush(1);

(在 Perl 5.14 之前,必须先明确地use IO::Handle;。)

虽然你可以使用select来临时“捕获”print的输出,如下所示

{
    my $old_handle = select $new_handle;

    # This goes to $new_handle:
    print "ok 1\n";
    ...

    select $old_handle;
}

你可能会发现局部化类型全局变量更容易

{
    local *STDOUT = $new_handle;

    print "ok 1\n";
    ...
}

两者并不完全等价,但后者可能更清晰,并且如果包装代码死亡,它将恢复 STDOUT。不同之处在于,在前者中,仍然可以通过在print语句中明确使用它(如print STDOUT ...)来访问原始 STDOUT,而在后者中,STDOUT 句柄本身的含义已暂时更改。

可移植性问题:perlport 中的“select”

select RBITS,WBITS,EBITS,TIMEOUT

这将使用指定的位掩码调用 select(2) 系统调用,可以使用 filenovec 构建这些位掩码,如下所示

my $rin = my $win = my $ein = '';
vec($rin, fileno(STDIN),  1) = 1;
vec($win, fileno(STDOUT), 1) = 1;
$ein = $rin | $win;

如果您想在许多文件句柄上进行选择,您可能希望编写一个类似这样的子例程

sub fhbits {
    my @fhlist = @_;
    my $bits = "";
    for my $fh (@fhlist) {
        vec($bits, fileno($fh), 1) = 1;
    }
    return $bits;
}
my $rin = fhbits(\*STDIN, $tty, $mysock);

通常的习惯用法是

my ($nfound, $timeleft) =
  select(my $rout = $rin, my $wout = $win, my $eout = $ein,
                                                         $timeout);

或者,为了在某些内容准备就绪后进行阻塞,只需执行此操作

my $nfound =
  select(my $rout = $rin, my $wout = $win, my $eout = $ein, undef);

大多数系统不会费心在 $timeleft 中返回任何有用的内容,因此在标量上下文中调用 select 只会返回 $nfound

任何位掩码也可以是 undef。如果指定了超时,则以秒为单位,可以是分数。注意:并非所有实现都能返回 $timeleft。如果没有,它们始终返回 $timeleft 等于提供的 $timeout

您可以通过这种方式休眠 250 毫秒

select(undef, undef, undef, 0.25);

请注意,select 是否在信号(例如 SIGALRM)后重新启动取决于实现。另请参阅 perlport 以了解有关 select 可移植性的说明。

出错时,select 的行为与 select(2) 完全相同:它返回 -1 并设置 $!

在某些 Unix 上,select(2) 可能会将套接字文件描述符报告为“准备好读取”,即使没有可用数据,因此任何后续的 read 都会阻塞。如果您始终在套接字上使用 O_NONBLOCK,则可以避免这种情况。有关更多详细信息,请参阅 select(2)fcntl(2)

标准 IO::Select 模块为 select 提供了更友好的用户界面,主要是因为它为您完成了所有位掩码工作。

警告:除了 POSIX 允许的情况外,不应尝试将缓冲 I/O(如 readreadline)与 select 混合,即使在 POSIX 系统上也只允许这样做。您必须改用 sysread

可移植性问题:perlport 中的“select”