Unix & Linux Stack Exchange is a question and answer site for users of Linux, FreeBSD and other Un*x-like operating systems. Join them; it only takes a minute:

Sign up
Here's how it works:
  1. Anybody can ask a question
  2. Anybody can answer
  3. The best answers are voted up and rise to the top

Imagine the following file structure:

foo.bar.1
blabla
moreblabla
relevant=yes
foo.bar.2
relevant=no
foo.bar.3
blablabla
foo.bar.4
relevant=yes

I want to retrieve all foo.bar lines where within the block following themselves and before the next foo.bar there is a line stating relevant=yes.

So the output should be:

foo.bar.1
foo.bar.4

I could of course write a program/script iterating through the lines, remembering the foo.bars and print them when there is a line saying relevant=yes following them an before the next foo.bar. But I thought there might be an out-of-the box way using standard Unix utilities (grep/sed/awk)?

Thanx for any hints!

share|improve this question
    
Chose awk solution as "answer" for being the clearest one in syntax. – hal9000 Feb 3 at 20:07
up vote 5 down vote accepted

If the input is processed line by line, then processing needs to go like this:

  • if the current line is foo.bar, store it, forgetting any previous foo.bar line that wasn't enabled for output;
  • if the current line is relevant=yes, this enables the latest foo.bar for output.

This kind of reasoning is a job for awk. (It can also be done in sed if you like pain.)

awk '
    /^foo\.bar/ { foobar = $0 }
    /^relevant=yes$/ {if (foobar != "") {print foobar; foobar = ""}}
'
share|improve this answer
    
Thanks for giving this awk solution. Pretty straight-forward. – hal9000 Feb 2 at 19:55

Here's one way with sed:

sed '/foo\.bar/h;/relevant=yes/!d;x;/foo\.bar/!d' infile

Lines matching foobar are copied to hold space. All lines, except those matching relevant=yes are deleted. Exchange hold space with pattern space (this only happens when lines match relevant=yes) and delete if it doesn't match foobar.

share|improve this answer
    
I get an bash: !d': event not found, what am I doing wrong? – user unknown Feb 1 at 0:24
1  
@userunknown - you're using bash... try with ! d that is, insert a space after each ! or try set +H before running the sed command – don_crissti Feb 1 at 9:46
    
Thanks for giving this sed solution as well. Looks a little more painful than the awk-one imho as Gilles pointed out above. ;-) But I like it just as well. – hal9000 Feb 3 at 18:54
    
@hal9000 - You're welcome ! I don't quite understand what's so painful about it but let's leave it at that. – don_crissti Feb 3 at 19:00
    
@don_crissti - Sorry, sounded a little unfair. I admit it not being painful. It is just a very very little less straight-forward than awk imho. Was more catching the term Gilles used. Explanation: For someone not knowing sed perfectly well (count me in), the concept of spaces and exchanging them doesn't come clear just by looking at the syntax. The awk solution might be easier to grasp if you do not know either sed nor awk. But again, I loved to see a sed solution to this. This is why I pointed sed out as a tag. – hal9000 Feb 3 at 20:17

Pythonic way:

>>> with open("/home/xieerqi/textfile.txt") as file:
...   for line in file:
...       if line.__contains__("foo"):
...          VAR = line
...       if line.__contains__("relevant=yes"):
...          print VAR
... 
foo.bar.1

foo.bar.4

Put together in a script:

DIR:/xieerqi
skolodya@ubuntu:$ chmod +x  relevance.py                                       

DIR:/xieerqi
skolodya@ubuntu:$ ./relevance.py textfile.txt                                  
foo.bar.1
foo.bar.4

DIR:/xieerqi
skolodya@ubuntu:$ cat relevance.py                                             
#!/usr/bin/env python
import sys

with open(sys.argv[1]) as file:
   for line in file:
       if line.__contains__("foo"):
          VAR = line.strip("\n")
       if line.__contains__("relevant=yes"):
          print VAR
share|improve this answer
    
Thank you for the python solution though I prefer the other two solutions in this case. They are shorter and are what I meant when writing "out-of-the-box" in my initial question. But in the end your solution is just as fine. One thing though is taht when the pattern is a regular expression. awk and sed can handle them immediately whereas Python needs to be modified a little. (import re) – hal9000 Feb 3 at 20:04
    
:) Fair comment - awk and sed are always better for text processing, and I do prefer them myself ( in fact awk is a big part of my reputation on the other site, askubuntu.com ), however both sed and awk solutions have been posted, so I thought I'd bright something else to the table. Hope in the end my answer was beneficial in some way to you and other users ! – Serg Feb 3 at 20:20

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

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