在模式之间返回多行的高效非贪婪方法
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 个问题:
- 这让我感到畏缩,因为我知道这很糟糕
- 速度慢;我必须浏览数十万个条目,而且花费的时间太长
- 有时,如我示例中的第 2 小节、第 4 小节和第 5 小节,'manchu' 上方没有文本。在这种情况下,它错误地 returns 一个 foo,这不是我想要的。
我想我可以用 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; q
。 q
打印结果后直接退出
使用 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" 和上一行。
我有这样一个文件:
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 个问题:
- 这让我感到畏缩,因为我知道这很糟糕
- 速度慢;我必须浏览数十万个条目,而且花费的时间太长
- 有时,如我示例中的第 2 小节、第 4 小节和第 5 小节,'manchu' 上方没有文本。在这种情况下,它错误地 returns 一个 foo,这不是我想要的。
我想我可以用 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; q
。 q
打印结果后直接退出
使用 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" 和上一行。