如何从perl中的<stdin>进行嵌套读取?

时间:2016-12-05 20:16:58

标签: perl stdin

我正在编写一个脚本来解析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);

2 个答案:

答案 0 :(得分:4)

foreach遍历列表,因此<>位于列表上下文中,因此它会从文件句柄中读取所有内容。所以当你将$in传递给子时,它上面没有任何输入。请参阅I/O Operators in perlop

您可以一次读取一行while (my $line = <$in>),但我不确定这是否会影响您算法的其余部分。

或者,如果您提前阅读了所有输入,那么为什么不只是使用一系列行。

答案 1 :(得分:0)

当您说foreach my $line ( <$in> )时,这会导致perl在开始循环之前读取整个$in文件句柄。你可能想要的更像是这样:

while (defined(my $line = <$in>))

这样一次只会读取一行,并在完成后将其丢弃。