在Python中使用grep -r
我想在Python中实现Unix命令'grep -r'的功能。我知道可以用commands.getstatusoutput(),但现在我不想用这个。我想出了这个:
def grep_r (str, dir):
files = [ o[0]+"/"+f for o in os.walk(dir) for f in o[2] if os.path.isfile(o[0]+"/"+f) ]
return [ l for f in files for l in open(f) if str in l ]
不过,这个当然没有用到正则表达式,它只是检查'str'是否是'l'的子字符串。所以我尝试了以下这个:
def grep_r (pattern, dir):
r = re.compile(pattern)
files = [ o[0]+"/"+f for o in os.walk(dir) for f in o[2] if os.path.isfile(o[0]+"/"+f) ]
return [ l for f in files for l in open(f) if r.match(l) ]
但是这个不行,它没有给我任何匹配的结果,即使之前的函数能找到匹配。到底是什么改变了?我可以把它拆成一堆嵌套的循环,但我更想要简洁,而不是可读性。
相关问题:
5 个回答
3
把所有这些代码放到一个叫做 pygrep 的文件里,然后运行命令 chmod +x pygrep:
#!/usr/bin/python
import os
import re
import sys
def file_match(fname, pat):
try:
f = open(fname, "rt")
except IOError:
return
for i, line in enumerate(f):
if pat.search(line):
print "%s: %i: %s" % (fname, i+1, line)
f.close()
def grep(dir_name, s_pat):
pat = re.compile(s_pat)
for dirpath, dirnames, filenames in os.walk(dir_name):
for fname in filenames:
fullname = os.path.join(dirpath, fname)
file_match(fullname, pat)
if len(sys.argv) != 3:
u = "Usage: pygrep <dir_name> <pattern>\n"
sys.stderr.write(u)
sys.exit(1)
grep(sys.argv[1], sys.argv[2])
9
你可能想用 search() 而不是 match(),因为 search() 可以找到行中间的匹配项,具体可以参考这个链接:http://docs.python.org/library/re.html#matching-vs-searching
另外,你的代码结构和意图有点不清晰。我已经把它调整得更符合Python的风格了。
def grep_r (pattern, dir):
r = re.compile(pattern)
for parent, dnames, fnames in os.walk(dir):
for fname in fnames:
filename = os.path.join(parent, fname)
if os.path.isfile(filename):
with open(filename) as f:
for line in f:
if r.search(line):
yield line
6
re.match 只检查字符串的开头。
可以使用 re.search()
来自 官方文档:
Python 提供了两种基于正则表达式的基本操作:match 只在字符串的开头检查是否匹配,而 search 则会在字符串的任何位置检查是否匹配(这也是 Perl 默认的行为)。