Efficient unwanted method to return multiple lines between patterns

I have a file like this:

bar 1
 foo 1
  how now
  manchu 50
 foo 2
  brown cow
  manchu 55
 foo 3
  the quick brown
  manchu 1
bar 2
 foo 1
  fox jumped
  manchu 8
 foo 2
  over the
  manchu 20
 foo 3
  lazy dog
  manchu 100
 foo 4
  manchu 5
 foo 5
  manchu 7
bar 3
bar 4

I want to find "manchu 55" and get:

FOONUMBER = 2

(Foo # above 'manchu 55')

BARNUMBER = 1

(Bar # higher than foo)

PHRASETEXT = "brown cow"

(Text on the line above "manchu 55")

Therefore, I can ultimately deduce:

brown cow, bar 1, foo 2.

So far I have been doing this with some really ugly grep code like:

FOONUMBER=`grep -e "manchu 55" -e ^" foo" -e ^"bar" | grep -B 1 "manchu 55" | grep "foo" | awk '{print $2}'`

BARNUMBER=`grep -e ^" foo $FOONUMBER" -e ^"bar" | grep -B 1 "foo $FOONUMBER" | grep "bar" | awk '{print $2}'`

PHRASETEXT=`grep -B 1 "manchu 55" | grep -v "manchu 55"`

There are 3 problems with this code:

  • It makes me cringe because I know it badly.
  • It is slow; I have to go through hundreds of thousands of records, and it takes too long.
  • sometimes, like in bar 2, foo 4 and 5 in my example, there is no text above “manchu”. In this case, it returns foo incorrectly, which I don't want.

, sed, - :

FOONUMBER=`sed -n '/foo/,/manchu 55/p' | grep foo | awk '{print $2}'

, sed . AWK , , , , , .

, , , - , , . , , , , , , , .

+4
2

awk:

awk -v nManchu=55 -v OFS=", " '
  $1 == "bar" {bar = $0}    # store the most recently seen "bar" line
  $1 == "foo" {foo = $0}    # store the most recently seen "foo" line 
  $1 == "manchu" && $2 == nManchu {print prev, bar, foo} 
  {prev = $0}               # remember the previous line
' file

  brown cow, bar 1,  foo 2

"nManchu = 100"

  lazy dog, bar 2,  foo 3

, , 3 , "", "foo" .

+6

sed -n '/foo/ { s/.*foo\s*//; h }; /manchu 55/ { x; p }' filename

:

/foo/ {         # if you see a line with "foo" in it,
  s/.*foo\s*//  # isolate the number
  h             # and put it in the hold buffer
}
/manchu 55/ {   # if you see a line with "manchu 55" in it,
  x             # exchange hold buffer and pattern space
  p             # and print the pattern space.
}

, foo manchu 55. ,

 sed -n '/manchu 55/ { x; p }; h'

manchu 55.

 sed -n '/manchu 55/ { x; p }; s/^\s*//; h'

.

, manchu 55 , x; p x; p; q. q , .

+2

All Articles