在Python中使用grep搜索文件

1 投票
3 回答
6835 浏览
提问于 2025-04-17 16:46

我在这里查找关于grep的答案,但找不到合适的。大家似乎都在讨论如何在文件中搜索一个字符串,而不是从文件中读取字符串列表。我已经有一个可以用的搜索功能,但grep的速度快得多。我在一个名为sn.txt的文件里有一串字符串(每行一个字符串,没有分隔符)。我想在另一个文件(Merge_EXP.exp)中查找包含这些字符串的行,并把结果写入一个新文件。要知道,我要搜索的文件有五十万行,所以在里面找几千个字符串没有grep的话要花好几个小时。

当我在Windows的命令提示符下运行这个命令时,几分钟就能完成:

grep --file=sn.txt Merge_EXP.exp > Merge_EXP_Out.exp

我想知道如何从Python中调用这个相同的过程?我不太想要Python中的其他替代方案,因为我已经有一个可以用但速度慢的。如果你觉得能显著提高我的那个方法的性能,那也可以。

def match_SN(serialnumb, Exp_Merge, output_exp):
    fout = open(output_exp,'a')
    f = open(Exp_Merge,'r')
    # skip first line
    f.readline()
    for record in f:
        record = record.strip().rstrip('\n')
        if serialnumb in record:
            fout.write (record + '\n')
    f.close()
    fout.close()

def main(Output_CSV, Exp_Merge, updated_exp):

    # create a blank output
    fout = open(updated_exp,'w')

    # copy header records
    f = open(Exp_Merge,'r')
    header1 = f.readline()
    fout.write(header1)
    header2 = f.readline()
    fout.write(header2)
    fout.close()
    f.close()

    f_csv = open(Output_CSV,'r')
    f_csv.readline()
    for rec in f_csv:
        rec_list = rec.split(",")
        sn = rec_list[2]
        sn = sn.strip().rstrip('\n')
        match_SN(sn,Exp_Merge,updated_exp)

3 个回答

0

我觉得你给问题起的标题不太合适:你想做的事情其实相当于数据库中的JOIN操作。你可以在这种情况下使用grep,因为你其中一个文件只有键,没有其他信息。不过,我觉得将来你的sn.txt文件可能也会包含额外的信息。

所以我建议你解决一个更通用的情况。这里有几种解决方案:

  • 把所有数据导入数据库,然后进行左连接(LEFT JOIN)或者类似的操作
  • 使用Python的大数据工具

对于后者,你可以尝试numpy,或者因为你在处理字符串,推荐使用pandas。根据我的经验,Pandas有一个优化的合并功能,速度非常快(底层使用了cython)。

以下是用pandas解决你问题的伪代码。虽然这接近真实代码,但我需要知道你想匹配的列名。我假设在sn.txt中有一列叫key,而在merge_txt中匹配的列叫sn。我还注意到你在merge_exp中有两行标题,建议你查阅相关文档了解更多。

# PSEUDO CODE (but close)
import pandas
left = pandas.read_csv('sn.txt')
right = pandas.read_csv('merge_exp.exp')
out = pandas.merge(left, right, left_on="key", right_on="sn", how='left')
out.to_csv("outx.txt")
0

这是一个优化过的纯Python代码版本:

def main(Output_CSV, Exp_Merge, updated_exp):
    output_list = []

    # copy header records
    records = open(Exp_Merge,'r').readlines()
    output_list = records[0:2]

    serials = open(Output_CSV,'r').readlines()
    serials = [x.split(",")[2].strip().rstrip('\n') for x in serials]

    for s in serials:
        items = [x for x in records if s in x]
        output_list.extend(items)

    open(updated_exp, "w").write("".join(output_list))

main("sn.txt", "merge_exp.exp", "outx.txt")

输入

sn.txt文件:

x,y,0011
x,y,0002

merge_exp.exp文件:

Header1
Header2
0011abc
0011bcd
5000n
5600m
6530j
0034k
2000lg
0002gg

输出

Header1
Header2
0011abc
0011bcd
0002gg

试试看这个,看看它需要多长时间...

0

当我使用grep的完整路径时,它可以正常工作(我给它传递了grep_loc、Serial_List和Export这些参数):

import os

Export_Dir = os.path.dirname(Export)
Export_Name = os.path.basename(Export)

Output = Export_Dir + "\Output_" + Export_Name
print "\nOutput: " + Output + "\n"

cmd = grep_loc + " --file=" + Serial_List + " " + Export + " > " + Output
print "grep usage: \n" + cmd + "\n"
os.system(cmd)
print "Output created\n"

撰写回答