Beefy Boxes and Bandwidth Generously Provided by pair Networks
laziness, impatience, and hubris
 
PerlMonks  

Print n lines after a matched line

by sreek3502 (Novice)
on Jun 13, 2018 at 18:14 UTC ( #1216577=perlquestion: print w/replies, xml ) Need Help??
sreek3502 has asked for the wisdom of the Perl Monks concerning the following question:

I have an input file having following contents

SCHEDULE "TEST"

DESCRIPTION "Do Some stuff"

MINUTE "53"

HOUR "21"

SCHEDULE "DUMMY CHECK"

DESCRIPTION "Do some stuff"

Check something

INTERVAL "10m"

MINUTE "50"

HOUR "21"

I need to match the 3rd line after the matched line SCHEDULE "DUMMY CHECK" which is INTERVAL "10m". I have written the below code for that purpose, however i'm not sure if this is the exact way of doing it, or do we have any simple other logics.

use strict; use warnings; my $file = "input.txt"; my @data; open (IN,"<","$file"); my $count = 0; while (<IN>) { $count = 1 if /SCHEDULE\s"(DUMMY\sCHECK)".*/; if ($count >= 1 and $count <= 6) { @data = $_; print @data; $count++; } }

Replies are listed 'Best First'.
Re: Print n lines after a matched line
by Discipulus (Monsignor) on Jun 13, 2018 at 18:36 UTC
    Hello sreek3502,

    If your input is somehow fixed in it's content the easiest thing is using the flip-flop operator (see flip flop at my library and in perlop):

    while (<DATA>){ print if /SCHEDULE "DUMMY CHECK"/ .. /INTERVAL/; }

    If you just want to print 3 lines after a match (but notice you have empty lines that count! i used 6 lines..) you can use or a count, as you already have done, or use the special variable $. (explained in perlvar ) that is line number:

    my $switch; while (<DATA>){ $switch = $. if /SCHEDULE "DUMMY CHECK"/; if ( $switch and $. <= $switch + 6){ print; } }

    As final note @data = $_; does not make muche sense for me: you want to split the line? dont forget also to chomp

    L*

    There are no rules, there are no thumbs..
    Reinvent the wheel, then learn The Wheel; may be one day you reinvent one of THE WHEELS.
Re: Print n lines after a matched line
by shmem (Chancellor) on Jun 14, 2018 at 12:39 UTC

    Discipulus solution above is very elegant. Here's the correction of the error in your script:

    use strict; use warnings; my $file = "input.txt"; my @data; open (IN,"<","$file"); my $count = 0; while (<IN>) { $count = 1 if /SCHEDULE\s"(DUMMY\sCHECK)".*/; if ($count >= 1 and $count <= 6) { - @data = $_; - print @data; + $_ = <IN>; + print; $count++; } }

    You did not read the next line off your input file descriptor.

    perl -le'print map{pack c,($-++?1:13)+ord}split//,ESEL'
Re: Print n lines after a matched line
by haukex (Abbot) on Jun 13, 2018 at 18:44 UTC

    Crossposted to StackOverflow. Crossposting is acceptable, but it is considered polite to inform about it, so that efforts are not duplicated.

Re: Print n lines after a matched line
by LanX (Bishop) on Jun 14, 2018 at 17:06 UTC
Re: Print n lines after a matched line
by Marshall (Abbot) on Jun 14, 2018 at 17:08 UTC
    I like the flip-flop operator as demo'd by Discipulus. If I don't use that, I often use the following pattern. The flip-flop operator maintains the state of whether you are inside the record or not - that's a very nice feature. Anyway, without the flip-flop, instead of maintaining a flag to tell me if I'm in the record or not, I call a subroutine to keep track of the "state". This may be a bit "wordy", but the logic is crystal clear (at least to me).
    #!/usr/bin/perl use strict; use warnings; while (defined (my $line = <DATA>)) { process_record($line) if $line =~ /^\s*SCHEDULE "DUMMY CHECK"/; } sub process_record { my $line = shift; #the "trigger line" print $line; for (1..3) #maybe have regex for "end of record"? { my $line = <DATA>; print $line; } print "\n"; #just a spacer } =prints SCHEDULE "DUMMY CHECK" DESCRIPTION "Do some stuff" Check something INTERVAL "10m" SCHEDULE "DUMMY CHECK" DESCRIPTION "Do some more stuff" Check something INTERVAL "30m" =cut __DATA__ SCHEDULE "TEST" DESCRIPTION "Do Some stuff" MINUTE "53" HOUR "21" SCHEDULE "DUMMY CHECK" DESCRIPTION "Do some stuff" Check something INTERVAL "10m" MINUTE "50" HOUR "21" SCHEDULE "TEST" DESCRIPTION "Do Some stuff" MINUTE "53" HOUR "21" SCHEDULE "DUMMY CHECK" DESCRIPTION "Do some more stuff" Check something INTERVAL "30m" MINUTE "50" HOUR "21"
Re: Print n lines after a matched line
by taint (Chaplain) on Jun 13, 2018 at 22:18 UTC

    It's difficult to know how to best respond, or provide the best answer, without a bit more context. IOW you mention match, which is really a simple matter, as described in the linked Perl documentation -- especially if the given text file is static.

    But, then again. If you need to further process that file, or perhaps another file. The (best) answer might be quite different.

    tl;dr;
    You will need to help us, help you.

    Evil is good, for without it, Good would have no value
    λɐp ʇɑəɹ⅁ ɐ əʌɐɥ puɐ ʻꜱdləɥ ꜱᴉɥʇ ədoH

Re: Print n lines after a matched line
by sundialsvc4 (Abbot) on Jun 14, 2018 at 14:23 UTC

    If there is any identifying feature of that “third line” then I would suggest basing your logic upon that feature rather than “third line” because you really shouldn’t write code that assumes that the supplier of that file won’t change his program and, in so doing, break yours.

    The “classic” text-file processing tool an inspiration for Perl was awk, whose programs consist of regular-expressions followed by code that is to be executed when that expression is matched.   Simple and effective.   Perl, today, is by far the preferable tool Larry Wall did a great job but the concept of awk is classic and well worth studying for ideas.   In fact, there is an a2p tool that will convert Awk scripts to Perl.

    “Third line” logic, of course, is easy to do:

    my $counter = -1; (so it's never zero until decrement does it) while (<IN>) { if /SCHEDULE/ { (use right regex here) $counter = 2; } else if ($counter-- == 0) { // third line } }
      $ cat sd.pl my $counter = -1; # (so it's never zero until decrement does it) while (<IN>) { if /SCHEDULE/ { # (use right regex here) $counter = 2; } else if ($counter-- == 0) { // third line } } $ perl -cw sd.pl syntax error at sd.pl line 3, near "if /SCHEDULE/" syntax error at sd.pl line 6, near "else" sd.pl had compilation errors. $

      I've written that after a long period of simply ignoring sundialsvc4's posts, I felt obliged to upvote a couple that actually seemed helpful. The flip side is that I'm now obliged to pay attention to and downvote the crappy ones, e.g., this. Life used to be so simple.


      Give a man a fish:  <%-{-{-{-<

      (Shrug ...)   Down-vote if you want to, but if the line-of-interest begins with INTERVAL, then I would test for that.   In classic awk fashion, the SCHEDULE line maybe captures some information (and sets a flag to indicate that it has been seen), and the INTERVAL-line handler actually does the interesting work.

      Upstream programs do change ... they change all the time ... and so your down stream program has two important responsibilities (IMHO) which you should plan for:

      1. It should be resilient to changes in the upstream program.   If someone legitimately adds a line of output, your program should not break.
      2. It should be reasonably suspicious of its input file, since if a bug has crept into that upstream program, the downstream program is in an ideal position to sound the alarm.   (Otherwise it is frankly extremely-probable that the bug won’t be detected.)

      Although awk is a fairly simplistic program in some ways, its very-straightforward design is extremely powerful and you should make yourself aware of how it does things.   (Then, “write it the same way, in Perl.”)   In the almost half-a-century since the original program was written, certain data-processing requirements have not changed and never will.   Its approach still works, and it is, indeed, resilient.   @Larry was using this program when Perl 1.0 became a gleam in his eyes . . .

        "down-vote if you want to"

        Because despite being posted on a perl forum, and regardless of your self proclaimed abilities this isn't valid code, and has errors a beginner would have been able to spot within the first few hours of the language. You also responded to yourself again, but perhaps talking to yourself is the only time anything makes sense to you.

Log In?
Username:
Password:

What's my password?
Create A New User
Node Status?
node history
Node Type: perlquestion [id://1216577]
Approved by taint
Front-paged by haukex
help
Chatterbox?
and all is quiet...

How do I use this? | Other CB clients
Other Users?
Others musing on the Monastery: (3)
As of 2018-07-22 09:14 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?
    It has been suggested to rename Perl 6 in order to boost its marketing potential. Which name would you prefer?















    Results (453 votes). Check out past polls.

    Notices?