在单个 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?? ??
>
我想编写 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?? ??
>