4

I'm trying to wrap my mind around this task. I want from the following output, to exclude all the lines that contain Auto-installed: 1 and the 2 lines before. I was naively thinking that grep -v -B2 string will solve the problem... needless to say, only makes it worse.

This is the content:

Package: libopencore-amrwb0
Architecture: amd64
Auto-Installed: 1

Package: transfig
Architecture: amd64
Auto-Installed: 0

Package: xfig-libs
Architecture: amd64
Auto-Installed: 1

Package: xaw3dg
Architecture: amd64
Auto-Installed: 0

And this is how the results look:

Package: transfig
Architecture: amd64
Auto-Installed: 0

Package: xaw3dg
Architecture: amd64
Auto-Installed: 0

(note, empty lines are not showing, if it doesn't show empty lines is a plus but is not required, also results should include the Packages which Auto-Installed values is 0)

I know I can match line breaks but either end in not printing anything or printing everything but the lines breaks in between.

Any solution is acceptable, it doesn't have to be grep (it even can be emacs).

  • Your text says delete the two lines before, your sample output says the two lines before and any redundant surrounding blank lines. Which? – jthill Nov 18 '13 at 3:38
  • @Braiam - see my updates, I show how to do this w/ grep using your logic. – slm Nov 18 '13 at 5:53
6

I'm not sure how structured your data is but if it is just as you show, how about the following:

grep -B2 'Auto-Installed: [^1]'

That assumes that every stanza includes an Auto-Installed line, which might not be correct.

Here's an awk program which I think does exactly as you asked.

awk 'BEGIN{deleted=3}
     !deleted{printf "%s",l[NR%3]}
     deleted {--deleted}
     {l[NR%3]=/./?$0"\n":$0}
     /Auto-Installed: 1/{deleted=3}
     END{for(i=NR+deleted;i<NR+3;++i)printf "%s",l[i%3]}'
3

I think this'll do ya

sed ':a
     $!N                          # slurp
     /Auto-Installed: 1/s/.*//    # kill all buffered on match
     $!{/\n.*\n/{P;D}}            # P/D any third line, D cycles w/o read
     $!ba                         # if no P/D, cycle w/o read anyway
    '
  • I tried, this works fine too, just keeps blank lines which can easily be cleaned up a variety of ways! – slm Nov 18 '13 at 3:47
  • I'd do it with a second sed 'cause I'm lazy :-) – jthill Nov 18 '13 at 3:47
  • 2
    Me too, others would give us a hard time for using too many commands but it's easier to grep -v "^$" afterwards to get rid of them. 73% of scripting is doing what's easier/lazier. – slm Nov 18 '13 at 3:48
3

Instead of even trying to deal with excluding them, why not just select the opposite lines, which happen to be what you want anyway?

$ grep -B 2 "Auto-Installed: 0" data.txt 
Package: transfig
Architecture: amd64
Auto-Installed: 0

Excluding sections that have "Auto-Installed: 1"

If you'd like to use grep but using your logic to approach the problem where you exclude sections that contain "Auto-Installed: 1" I didn't come up with this approach using the PCRE facility within GNU grep.

$ grep -B2 -P 'Auto-Installed: (?!1)' data.txt 

Example

$ grep -B2 -P 'Auto-Installed: (?!1)' data.txt 
Package: transfig
Architecture: amd64
Auto-Installed: 0

The above makes use of Perl's lookahead feature, (?!..). This allows us to do the match looking for lines that don't contain a value of 1, after Auto-Installed:. We then tell grep to display 2 lines (-B2) before then "match".

  • That's a nice one. – jthill Nov 18 '13 at 3:44
  • Yeah, I wanted to use the double-clawed hammer :(. But as I didn't found a way to this through and was wondering if it was possible. ;) – Braiam Nov 18 '13 at 3:50
  • @Braiam - yeah grep can't do the range and the -v switch. – slm Nov 18 '13 at 3:55
2

What you have is in fact records separated by blank lines. Rather than coding up some brittle parsing that depends on the order and number of lines, use a tool like awk or perl to process records separated by blank lines (paragraph mode).

awk -F '' '! /^Auto-Installed: 1$/'
  • I'm expecting that the lines before Auto-Installed: 0 appears (which is determinant). I'm trying to build a package/autoinstalled relationship (which is my final goal) where I'm interested in the entries where Auto Installed is 0. – Braiam Nov 19 '13 at 0:52
  • @Braiam The lines before Auto-Installed: 0 do appear. -F with an empty argument sets awk to paragraph mode (this is similar to the Perl code in terdon's answer). – Gilles Nov 19 '13 at 0:56
2

And here's the obligatory Perl way:

perl -000ne 'print unless /Auto-Installed: 1/' file

The magic is the -000, this turns on Perl's paragraph mode which makes it split the files into paragraphs. In other words, records are separated by two or more consecutive \n characters.

This will also print the blank line between entries, to get rid of that, you could run

perl -000ne 'print unless /Auto-Installed: 1/' file | grep .

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.