在模式之间返回多行的高效非贪婪方法

Efficient non-greedy method of returning multiple lines between patterns

我有这样一个文件:

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

我想搜索 'manchu 55' 并接收:

FOONUMBER=2

(上面的foo#'manchu 55')

BARNUMBER=1

(foo 上方的 # 栏)

PHRASETEXT="brown cow"

(上面一行的文字'manchu 55')

所以我最终可以输出:

brown cow, bar 1, foo 2.

到目前为止,我已经使用一些非常丑陋的 grep 代码完成了此操作,例如:

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

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

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

这段代码有 3 个问题:

我想我可以用 sed 做到这一点,做类似的事情:

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

不幸的是 sed 太贪心了。我一直在阅读有关 AWK 和状态机的资料,这似乎是一种更好的方法,但我仍然不太了解它,无法进行设置。

正如您现在可能已经确定的那样,编程并不是我谋生的工作,但最终我还是受到了这种压力。我希望重写我已经拥有的东西,以提高效率,并希望不会太复杂,因为其他一些没有编程学位的可怜的草皮可能最终不得不在将来的某个日期支持对其进行的任何更改。

我会建议

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.
}

这将打印在 manchu 55 行之前的 foo 之后看到的最后一个数字。基本上可以用相同的方式提取小节编号,对于短语文本,您可以使用

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

在看到 manchu 55 之前保持行。或者可能

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

删除这样一行中的前导空格。

如果您确定文件中只有 manchu 55 行或者您只想要第一个匹配项,则可以将 x; p 替换为 x; p; qq打印结果后直接退出

使用 awk:

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

产出

  brown cow, bar 1,  foo 2

运行 "nManchu=100" 输出

  lazy dog, bar 2,  foo 3

这样做的好处是只通过文件一次,而不是解析文件 3 次以获得 "bar"、"foo" 和上一行。