我有一个这样的文件:

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' 并收到:



('manchu 55' 上面的 foo #)



(那个 foo 上方的栏 #)



('满族55'上方一行的文字)

所以我最终可以输出:



到目前为止,我已经用一些非常难看的 grep 代码完成了这个,比如:
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"`

这段代码有3个问题:
  • 这让我感到害怕,因为我知道这很糟糕
  • 很慢;我必须经过数十万个条目,而且花费的时间太长
  • 有时,如在我的示例中的第 2、foo 4 和 5 小节,“满语”上方没有文字。在这种情况下,它错误地返回一个 foo,这不是我想要的。

  • 我怀疑我可以用 sed 做到这一点,做类似的事情:
    FOONUMBER=`sed -n '/foo/,/manchu 55/p' | grep foo | awk '{print $2}'
    

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

    正如您现在可能已经确定的那样,编程不是我的谋生之道,但最终我受到了这种压力。我希望重写我已经拥有的内容,以提高效率,希望不会太复杂,因为其他一些没有编程学位的糟糕草皮可能最终不得不在 future 的某个日期支持对它的任何更改。

    最佳答案

    使用 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 次来获得 "bar"、"foo"和 prev 行。

    10-07 16:25
    查看更多