1

I have a file that is around 25000 lines. Take a look at my sample input and required output

INPUT:

zone name tommy
* pwwn xxxxxxxx
  pwwn xyzabcda
* pwwn xcvuytnm
zone name sammy
* pwwn akslapsl
* pwwn dfgsjasl
* pwwn xcvuytnm
zone name angelfalls
* pwwn xxxxxxxx
  pwwn xyzabcda
zone name Newyork
* pwwn xxxxxxxx
  pwwn xyzabcda

Desired Output:

zone name tommy
* pwwn xxxxxxxx
  pwwn xyzabcda
* pwwn xcvuytnm
zone name angelfalls
* pwwn xxxxxxxx
  pwwn xyzabcda
zone name Newyork
* pwwn xxxxxxxx
  pwwn xyzabcda

I want the output to exclude all the zones that contain a * in every line before the pwwn. In my example, zone name sammy has a * in all three pwwn lines, hence i excluded all * lines under zone name sammy.

Using solaris 5.10, Korn Shell.

3

Awk solution:

awk '/^zone /{ 
         if (f) print r;
         r = $0; f = 0; next 
     }
     { r = r ORS $0; if (/^[^*]* pwwn/) f = 1; }
     END{ if (f) print r }' file

The output:

zone name tommy
* pwwn xxxxxxxx
  pwwn xyzabcda
* pwwn xcvuytnm
zone name angelfalls
* pwwn xxxxxxxx
  pwwn xyzabcda
zone name Newyork
* pwwn xxxxxxxx
  pwwn xyzabcda
0

Here's how I would do this as a quick perl pipeline:

perl -p00e 's/\nzone/\n\nzone/g' inputfile \
| perl -n00e '$t = $_; s/^\*.*?\n//mg; print $t if /pwwn/' \
| perl -p00e 's/\n\n/\n/'

The first line adds a blank line between each record. The second line iterates over each record, checking to see if any pwwn lines remain after removing all lines starting with * within that record -- and if so, prints that record. The third line removes the blank lines separating each record.

0
$ awk -v RS='(^|\n)zone' '/\n[^*]/ { print "zone" $0 }' input 
zone name tommy
* pwwn xxxxxxxx
  pwwn xyzabcda
* pwwn xcvuytnm
zone name angelfalls
* pwwn xxxxxxxx
  pwwn xyzabcda
zone name Newyork
* pwwn xxxxxxxx
  pwwn xyzabcda

This awk script sets the Record Separator (RS) to either the beginning of the input file or a newline, followed by the word "zone". Then it prints each "record" that contains at least one newline not followed by a *.

It has to print the word "zone" along with $0 because awk automatically strips the RS from each input record.

NOTE: Because RS isn't just a newline by itself, $0 contains the newlines at the end of each line of input (this is very closely related to the reason mentioned above for why "zone" has to be printed). This means that there will be an extra blank line at the very end of the output. If this is a problem, the easiest way to get rid of it is with sed. e.g.

awk -v RS='(^|\n)zone' '/\n[^*]/ { print "zone" $0 }' input | sed '$d'

Finally, if the pwwn is an important part of the match criteria, then change the regular expression match in the script from /\n[^*]/ to /\n[^*] pwwn/. (with the sample input given, the output is identical, but may differ with your much larger real input)

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.