开发者

grep -r in python

i'd like to implement the unix command 'grep -r' in a python function. i know about commands.getstatusoutput(), but for now i don't want to use that. i came up with this:

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 ]

but that of course doesn't use a regex, it just checks if 'str' is a substring of 'l'. so i tried the following:

def grep_r (pattern, dir):
    r = re.compile(pattern)
    files = [ o[0]+"/"+f for o in os.walk(dir) for f in o[2]开发者_如何学C if os.path.isfile(o[0]+"/"+f) ]
    return [ l for f in files for l in open(f) if r.match(l) ]

but that doesn't work, it doesn't give me any matches even where the former function did. what changed? i could just split it up into a bunch of nested loops, but i'm more interested in being succinct than readable.


You might want to search() instead of match() to catch matches in the middle of lines, as noted in http://docs.python.org/library/re.html#matching-vs-searching

Also, the structure and intent of your code is quite hidden. I've pythonized it.

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


re.match only checks the beginning of the string.

Use re.search()

From the docs:

Python offers two different primitive operations based on regular expressions: match checks for a match only at the beginning of the string, while search checks for a match anywhere in the string (this is what Perl does by default).


Put all this code into a file called pygrep and 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])


import os, re

def grep_r(regex, dir):
    for root, dirs, files in os.walk(dir):
        for f in files:
            for m in grep(regex, os.path.join(root, f)):
                yield m

def grep(regex, filename):
    for i, line in enumerate(open(filename)):
        if re.match(regex, line): # or re.search depending on your default
           yield "%s:%d: %s" % (os.path.basename(filename), i+1, line)


why do you need to use regex?

path=os.path.join("/dir1","dir2","dir3")
pattern="test"
for r,d,f in os.walk(path):
    for files in f:
        for n,line in enumerate(open( os.path.join(r,files) ) ):
            if pattern in line:
                print "%s found in line: %d of file: %s" %(pattern, n+1, files)
0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜