在单个 Perl 脚本中,我可以关闭并重新打开 STDIN 吗?

In a single Perl script, can I close and re-open STDIN?

我想编写 perl 脚本,可以读取在调用脚本时给出的 STDIN,完成读取,然后以交互方式提示用户输入单行 STDIN。这一单行 STDIN 将告诉脚本如何进行。

在实际应用中,我希望脚本创建一个临时文件,报告临时文件的大小,然后询问用户是否真的要将整个临时文件打印到STDOUT,或者他们是否想要提供一个将被临时文件内容破坏的文件名。

如果我将 STDIN 作为文件名,则以下脚本的行为符合预期,但如果我将 STDIN 通过管道传递给脚本,则该脚本不起作用。

#! /usr/bin/perl
use strict; use warnings; 
my $count = 0;
while(<>)
{
    $count++;
}
print "you counted $count lines. Now do you want to proceed?";
my $answer = <STDIN>;
chomp $answer;
print STDERR "answer=$answer\n";
if ( $answer eq "yes" )
{
    print STDERR "you said $answer so we do something affirmative\n";
}
else
{
    print STDERR "you said $answer which is not \"yes\" so we do NOT proceed\n";
}

例如

> wc junk
     193    1042   11312 junk
> junk.pl junk
you counted 193 lines. Now do you want to proceed?yes
answer=yes
you said yes so we do something affirmative
> junk.pl junk
you counted 193 lines. Now do you want to proceed?no
answer=no
you said no which is not "yes" so we do NOT proceed
> cat junk | junk.pl
Use of uninitialized value $answer in scalar chomp at /Users/BNW/u/kh/bin/junk.pl line 10.
Use of uninitialized value $answer in concatenation (.) or string at /Users/BNW/u/kh/bin/junk.pl line 11.
answer=
Use of uninitialized value $answer in string eq at /Users/BNW/u/kh/bin/junk.pl line 12.
Use of uninitialized value $answer in concatenation (.) or string at /Users/BNW/u/kh/bin/junk.pl line 18.
you said  which is not "yes" so we do NOT proceed
you counted 193 lines. Now do you want to proceed?>

有点。也许。

首先,在您的第一个示例中,您“将 STDIN 作为文件名”是不正确的。 STDIN 始终是终端。 <> 正在从 ARGV 句柄而不是 STDIN 读取,因此 STDIN 稍后在您需要时可用。

第二个示例的问题是来自 cat 的管道是 STDIN。关闭它并重新打开它到它最初的样子对你没有任何作用,因为它仍然是一个耗尽的管道。

不过,许多系统都有一个特殊的设备 /dev/tty points to the controlling terminal of whichever process asks for it。在这样的系统上,您可以在它给出 EOF 后从 /dev/tty 重新打开 STDIN,并且您将获得用户从中调用您的程序的控制台,而不是他们最初作为 STDIN 提供给您的任何文件或管道。

感谢@hobbs。请注意,这两种方式都有效:将文件 junk 管道传输到脚本中或将 junk 作为 ARGV 传递。

> printf "line 1 \nline 222 \n" > junk
> perl -e 'use strict; use warnings; while(<>) { print; } my $stuff = "/dev/tty"; my $h; open $h, "<", $stuff or die "waah $stuff"; print "give answer:"; my $answer=<$h>; print "answer=$answer\n";' junk
line 1 
line 222 
give answer:This is an answer!
answer=This is an answer!

> cat junk | perl -e 'use strict; use warnings; while(<>) { print; } my $stuff = "/dev/tty"; my $h; open $h, "<", $stuff or die "waah $stuff"; print "give answer:"; my $answer=<$h>; print "answer=$answer\n";' 
line 1 
line 222 
give answer:So, what was it she was saying?? ?? 
answer=So, what was it she was saying?? ?? 

>