in reply to Re^2: How to print certain lines out of a text file.
in thread How to print certain lines out of a text file.

OK, Let's take a better look at what I truly meant to be more clear about.
My text file contains backup policy information, many backup policies. Each section (policy) starts with "Policy Name:".
I'm capturing that info and a few lines of data after "Policy Name:".
Further down in the text file is:
Policy Name: Backup_Monday Active: Yes Type: Normal ----- more various garbage in between ----- Granular Restore Info: No HW/OS/Client: PC Windows2003 ds1 PC Windows2003 ds2 PC Windows2003 ds3 PC Windows2003 ds4 PC Windows2000 ds5 PC Windows2000 ds6 (blank line here) (text file continues on to other policies in the file from here)
I check the line in the file to see if it has the pattern in it (HW/OS/Client) and if it does, I want to print that line and then keep printing each subsequent line until the (blank line) is reached. Exit that loop and go back to the main loop to look for another iteration of "Policy Name:". Keep doing this through all 122 backup policies.

I guess you'd say that I have a loop inside a loop.?

Make Sense? or have I muddied the water even more?

Thanks,
Dennis

Replies are listed 'Best First'.
Re^4: How to print certain lines out of a text file.
by graff (Chancellor) on Jul 31, 2010 at 22:33 UTC
    The description of the problem makes sense, but your guess about having a loop inside a loop is very muddled. And you still haven't shown any of your own code.

    By way of a better explanation, your solution should be something called a "state machine", where at any given time your program is in one of a finite set of "states" (it seems like two states will suffice here). Whether or not you print a given line depends on what state you're in, and there are certain lines that will cause a change of state. Make sense? Here's pseudo-code, which is pretty close to a perl solution:

    initial state is "0"; while there's a line that you've read from the file { set state to "1" if the current line contains "HW/OS/Client" print the current line if the current state is "1" (true) set state to "0" if the current line is blank (contains only white-sp +ace) }
    That should do what you want. Let us know if you have trouble turning that into perl code. (It shouldn't be hard.)
      graff, Here's all the code I have so far:
      #!/usr/bin/perl use strict; use warnings; my $PolicyName = ""; my $PolicyType = ""; my $ActivePolicy = ""; my $ClientServer = ""; open(INFILE, '<mas01_policy_dump.txt'); while(<INFILE>) { if ($_ =~ "Policy Name") { $PolicyName = $_; #print $line; } if ($_ =~ "Policy Type") { $PolicyType = $_; } if (($_ =~ "Active") && ($_ =~ "yes")) { $ActivePolicy = $_; print $PolicyName; print $PolicyType; print $ActivePolicy; } if ($_ =~ "HW/OS/Client") { while ($_) { next if /^$/; $ClientServer = $_; print $ClientServer; next; } } next; }

      Sorry, but I'm reading books and searching the internet while trying to learn about perl and write this script to do what I need done. So, I'm reading, writing, testing, fixing, reading, writing, testing, fixing.....it's a never ending cycle until I figure out how to do what I need done in Perl. I used to write Unix scripts but that's been years ago. I'm learning perl now because some of the production scripts I now have to help support are in Perl.
        You're very close.

        The nested "while" loop inside your fourth "if" block is wrong. In fact, as written, it will be an infinite loop, because you're not doing anything to change the value of "$_" -- it remains true "forever".

        Just reduce that fourth "if" block to one statement:

        if ($_ =~ "HW/OS/Client") { $ClientServer = $_; }
        Then add two more "if" blocks:
        if ( $ClientServer ) { print; } if ( /^\s*$/ ) { # true when the current line is blank $ClientServer = ""; }
        The point is that your "$ClientServer" variable works just fine as a state variable. Whenever it has any non-empty value, you print the current line of input, otherwise, you don't print. You go over all the lines of input with just the one outer "while" loop, and the various "if" conditions will do the right thing.

        (As shown above, the blank line following the data block of interest will be included in the output. If you don't want the blank line printed, just put that "if" block above the one that does the "print".)

Re^4: How to print certain lines out of a text file.
by sawdustar (Novice) on Jul 31, 2010 at 22:53 UTC
    And here is a snippet of what the text in the file looks like:
    Policy Name: BKUP_U_BOX01 Policy Type: Standard Active: yes Effective date: 06/22/2010 11:55:42 Client Compress: no Follow NFS Mounts: no Cross Mount Points: no Collect TIR info: no Block Incremental: no Mult. Data Streams: no Client Encrypt: no Checkpoint: no Policy Priority: 0 Max Jobs/Policy: Unlimited Disaster Recovery: 0 Collect BMR info: no Residence: box08-hcart-robot-acs-0 Volume Pool: box01_Onsite Server Group: *ANY* Keyword: (none specified) Data Classification: - Residence is Storage Lifecycle Policy: no Granular Restore Info: no HW/OS/Client: Solaris Solaris10 box01 Solaris Solaris10 box07 Solaris Solaris10 box08 Include: ALL_LOCAL_DRIVES Schedule: weekly_onsite Type: Full Backup Maximum MPX: 1 Synthetic: 0 PFI Recovery: 0
      You can use the range operator on the command line, like so:
      perl -ne "print if m{^\s*HW/OS/Client:} ... m{^\s*$}" mas01_policy_dum +p.txt

      which tells Perl to go through every line of the given file and print lines in-between (inclusive) two lines which match:
      • first line matches "HW/OS/Client", may begin with optional whitespace
      • last line matches a blank line
Re^4: How to print certain lines out of a text file.
by sawdustar (Novice) on Aug 06, 2010 at 17:00 UTC
    OK....I got things working a bit better now. Thought I'd post the code here for others to view in case I confused way too many people. :-)
    #!/usr/bin/perl use strict; use warnings; my $PolicyName = ""; my $PolicyType = ""; my $ActivePolicy = ""; my $ClientServer = ""; open(INFILE, '<mas01_policy_dump.txt'); while(<INFILE>) { chomp; if ( /^\s*$/ ) { # true when the current line is blank next; # No need to process blank lines here } if ( /------------------------------------------------------------ +/) { # Print all the seperators print "$_\n"; next; # No need for further checks } if ($_ =~ "Policy Name") { $PolicyName = $_; # New Policy, pay attention next; } if ($_ =~ "Policy Type") { $PolicyType = $_; next; } if ($_ =~ "Active") { if ($_ =~ "yes") { # Active Policy, we want this stuff $ActivePolicy = $_; print "$PolicyName\n"; print "$PolicyType\n"; print "$ActivePolicy\n"; next; } else { # Inactive policy, skip ahead while(<INFILE>) { if ( /------------------------------------------------ +------------/) { print $_; # CRLF included since no chomp last; } } } } # So should be active policy and non blank line from here if ($_ =~ "HW/OS/Client" ) { # Mutliline!! print "$_\n"; while(<INFILE>) { if ( /^\s*$/ ) { last; } # Blank line = end of lines chomp; print "$_\n"; } next; # I should hit this line only when $_ is blank } }

    Now, I'm not done with this just yet, but I wanted to post the code that I have so far that got me through the primary issue I was dealing with at the time.

    Thanks,
    Dennis