我如何在 perl 中从 <STDIN> 进行嵌套读取?
How do I do nested reads from <STDIN> in perl?
我正在编写一个脚本来解析来自 Java 的线程转储。出于某种原因,当我尝试从子例程内或嵌套循环内读取时,它根本不会进入嵌套循环。理想情况下,我希望能够在嵌套循环上对 STDIN 进行操作,否则你将不得不编写一些丑陋的状态转换代码。
在我使用 STDIN 之前,只是为了确保我的子程序没有指向 STDIN 的独立指针,我将其打开为 $in
。
当我运行它时,它看起来像下面这样。你可以看到它永远不会进入嵌套循环,尽管外循环有更多来自 STDIN 的文件要读取。
~/$ cat catalina.out-20160* | thread.dump.find.all.pl
in is GLOB(0x7f8d440054e8)
found start of thread dump at 2016-06-17 13:38:23 saving to tdump.2016.06.17.13.38.23.txt
in is GLOB(0x7f8d440054e8)
BEFORE NESTED STDIN
BUG!!!!
found start of thread dump at 2016-06-17 13:43:05 saving to tdump.2016.06.17.13.43.05.txt
in is GLOB(0x7f8d440054e8)
BEFORE NESTED STDIN
BUG!!!!
...
代码:
#!/usr/bin/perl
use strict;
use warnings;
use Getopt::Long;
use DateTime::Format::Strptime;
use DateTime::Format::Duration;
use Data::Dumper;
# DO NOT touch ARGV!
Getopt::Long::Configure("pass_through");
# cat catalina.out-* | thread.dump.find.all.pl
sub processThreadDump {
my $in=$_[0];
my $currentLine=$_[1];
my $prevLine=$_[2];
my $parsedDatetime=$_[2];
# 2016-09-28 09:27:34
$parsedDatetime=~ s/[ \-\:]/./g;
my $outfile="tdump.$parsedDatetime.txt";
print " saving to $outfile\n";
print " in is $in\n";
open(my $out, '>', $outfile);
print $out "$prevLine\n";
print $out "$currentLine\n";
print "BEFORE NESTED STDIN\n";
foreach my $line ( <$in> ) {
print "INSIDE NESTED STDIN\n";
$line =~ s/\R//g; #remove newlines
print $out "$line\n";
if( $line =~ m/JNI global references:/ ) {
print "PROPERLY LEFT NESTED STDIN\n";
close($out);
return;
} elsif( $line =~ m/Found \d+ deadlock\./ ) {
print "PROPERLY LEFT NESTED STDIN\n";
close($out);
return;
}
}
print "BUG!!!!\n";
close($out);
}
open(my $in, '<-');
print "in is $in\n";
my $prevLine;
# read from standard in
foreach my $line ( <$in> ) {
$line =~ s/\R//g; #remove newlines
if( $line =~ m/Full thread dump OpenJDK 64-Bit Server VM/ ) {
# we found the start of a thread dump
print "found start of thread dump at ${prevLine}";
processThreadDump($in, $line, $prevLine);
} else {
#print "setting prev line to $line\n";
$prevLine=$line;
}
}
close($in);
当你说 foreach my $line ( <$in> )
时,这会导致 perl 在开始循环之前读取整个 $in
文件句柄。你可能想要的更像这样:
while (defined(my $line = <$in>))
这将一次只读一行,读完后将其丢弃。
foreach
遍历 list,因此 <>
在列表上下文中,因此它从文件句柄中读取所有内容。因此,当您将 $in
传递给 sub 时,上面没有任何输入。参见 I/O Operators in perlop。
您可以一次读取一行,while (my $line = <$in>)
,但我不确定这是否会影响您算法的其余部分。
或者,如果您确实提前读取了所有输入,为什么不直接使用行数组呢。
我正在编写一个脚本来解析来自 Java 的线程转储。出于某种原因,当我尝试从子例程内或嵌套循环内读取时,它根本不会进入嵌套循环。理想情况下,我希望能够在嵌套循环上对 STDIN 进行操作,否则你将不得不编写一些丑陋的状态转换代码。
在我使用 STDIN 之前,只是为了确保我的子程序没有指向 STDIN 的独立指针,我将其打开为 $in
。
当我运行它时,它看起来像下面这样。你可以看到它永远不会进入嵌套循环,尽管外循环有更多来自 STDIN 的文件要读取。
~/$ cat catalina.out-20160* | thread.dump.find.all.pl
in is GLOB(0x7f8d440054e8)
found start of thread dump at 2016-06-17 13:38:23 saving to tdump.2016.06.17.13.38.23.txt
in is GLOB(0x7f8d440054e8)
BEFORE NESTED STDIN
BUG!!!!
found start of thread dump at 2016-06-17 13:43:05 saving to tdump.2016.06.17.13.43.05.txt
in is GLOB(0x7f8d440054e8)
BEFORE NESTED STDIN
BUG!!!!
...
代码:
#!/usr/bin/perl
use strict;
use warnings;
use Getopt::Long;
use DateTime::Format::Strptime;
use DateTime::Format::Duration;
use Data::Dumper;
# DO NOT touch ARGV!
Getopt::Long::Configure("pass_through");
# cat catalina.out-* | thread.dump.find.all.pl
sub processThreadDump {
my $in=$_[0];
my $currentLine=$_[1];
my $prevLine=$_[2];
my $parsedDatetime=$_[2];
# 2016-09-28 09:27:34
$parsedDatetime=~ s/[ \-\:]/./g;
my $outfile="tdump.$parsedDatetime.txt";
print " saving to $outfile\n";
print " in is $in\n";
open(my $out, '>', $outfile);
print $out "$prevLine\n";
print $out "$currentLine\n";
print "BEFORE NESTED STDIN\n";
foreach my $line ( <$in> ) {
print "INSIDE NESTED STDIN\n";
$line =~ s/\R//g; #remove newlines
print $out "$line\n";
if( $line =~ m/JNI global references:/ ) {
print "PROPERLY LEFT NESTED STDIN\n";
close($out);
return;
} elsif( $line =~ m/Found \d+ deadlock\./ ) {
print "PROPERLY LEFT NESTED STDIN\n";
close($out);
return;
}
}
print "BUG!!!!\n";
close($out);
}
open(my $in, '<-');
print "in is $in\n";
my $prevLine;
# read from standard in
foreach my $line ( <$in> ) {
$line =~ s/\R//g; #remove newlines
if( $line =~ m/Full thread dump OpenJDK 64-Bit Server VM/ ) {
# we found the start of a thread dump
print "found start of thread dump at ${prevLine}";
processThreadDump($in, $line, $prevLine);
} else {
#print "setting prev line to $line\n";
$prevLine=$line;
}
}
close($in);
当你说 foreach my $line ( <$in> )
时,这会导致 perl 在开始循环之前读取整个 $in
文件句柄。你可能想要的更像这样:
while (defined(my $line = <$in>))
这将一次只读一行,读完后将其丢弃。
foreach
遍历 list,因此 <>
在列表上下文中,因此它从文件句柄中读取所有内容。因此,当您将 $in
传递给 sub 时,上面没有任何输入。参见 I/O Operators in perlop。
您可以一次读取一行,while (my $line = <$in>)
,但我不确定这是否会影响您算法的其余部分。
或者,如果您确实提前读取了所有输入,为什么不直接使用行数组呢。