`cat 文件名 | grep -B 5 -C 5 foo`

2 投票
2 回答
1945 浏览
提问于 2025-04-15 13:28
for filename in os.listdir("."):
    for line in open(filename).xreadlines():
        if "foo" in line:
            print line

这段话的意思是,有一个简单的Python代码,可以实现类似于命令行中 cat filename | grep foo 的功能。不过,提问者想要的是一个更复杂的功能,类似于 cat filename | grep -B 5 -C 5 foo,也就是在查找包含“foo”的行时,还想要显示它前面和后面各5行的内容。提问者想知道应该如何修改上面的代码才能实现这个功能。

2 个回答

1

虽然我喜欢Alex的回答简单明了,但在处理大文件时,这种方法会消耗很多内存。那么我们来看看这个算法怎么样?

import os
for filename in (f for f in os.listdir(".") if os.path.isfile(f)):
    prevLines = []
    followCount = 0
    for line in open(filename):
        prevLines.append(line)
        if "foo" in line:
            if followCount <= 0:
                for prevLine in prevLines:
                    print prevLine.strip()  
            else:
                print line.strip()
            followCount = 5
        elif followCount > 0:
            print line.strip()
        followCount -= 1
        if len(prevLines) > 5:
            prevLines.pop(0)
7

最简单的方法是:

for filename in os.listdir("."):
    lines = open(filename).readlines()
    for i, line in enumerate(lines):
        if "foo" in line:
            for x in lines[i-5 : i+6]:
                print x,

可以根据需要添加行号、块之间的间隔等等;-)。

如果你碰到特别大的文本文件(比如说,比《圣经》大200-300倍的文件,而《圣经》的文本文件大约是4.3MB),我建议使用生成器来创建一个滑动窗口(也就是一个“先进先出”的行列表)。为了简单起见,这里只关注搜索文件中间的行,排除开头和结尾的几行(这需要额外的几个特殊处理的循环——所以我也返回索引...因为在这两个额外的循环中,索引不总是5!):

import collections

def sliding_windows(it):
  fifo = collections.deque()
  # prime the FIFO with the first 10 
  for i, line in enumerate(it):
    fifo.append(line)
    if i == 9: break
  # keep yielding 11-line sliding-windows
  for line in it:
    fifo.append(line)
    yield fifo, 5
    fifo.popleft()

for w, i in sliding_windows(open(filename)):
  if "foo" in w[i]:
    for line in w: print line,

我想我会把这些特殊处理的循环(以及处理非常少行的文件的担忧;-)留给大家自己练习,因为这一切都非常假设性。

给你几个小提示...:最后的“特殊处理循环”其实很简单——就是不断丢掉第一行,显然不需要再添加,因为没有更多的内容可以添加了……索引应该始终是5,当你得到一个窗口,5是最后的索引(也就是文件的最后一行)时,你就完成了;起始情况稍微复杂一点,因为你不想在读取前6行之前就返回结果,这时索引会是0(文件的第一行)……

最后,作为额外的挑战,考虑一下如何让这个方法也适用于非常短的文件!-)

撰写回答