让我们通过20行python代码实现一个简单的关键字搜索工具
目录遍历
首先我们来看如何实现目录遍历
目录遍历的过程很简单:
- 将目标路径作为当前目录
- 罗列出当前目录下的所有内容
- 判断每一个目标是否是文件夹。
- 如果是,进入该文件夹搜索(将文件夹路径改为当前路径,多级目录在此处会循环)
为什么我们要使用递归,与for对已知大小的列表的遍历相比,递归更适合与那些确定开始结束条件而过程不确定的情况。我们将初始路径设为起点,将目录下没有其他目录可以进入的情况设为终点
让我们来看如何通过递归的方式来遍历某个路径下的所有内容
1 2 3 4 5 6 7 | def search(path): content = os.listdir(path) for each in content: each_path = path + os.sep + each if os.path.isdir(each_path): search(each_path) print(each_path)#测试输出 |
- 第1行:首先我们先定义一个search函数,参数path是接收的路径
- 第2行:os.listdir(path) 将path路径下的所有(文件/文件夹)作为一个列表返回
- 第3行:使用for循环遍历当前目录
- 第4行:构建当前目录下文件的完整目录(当前目录/文件名称),os.sep为当前操作系统的分隔符
- 第5行:判断这个目标是否是文件夹
- 第6行:如果是,把这个文件夹作为新的路径像刚才那样再来一遍
- 第7行:最后在循环的后面我们加一个print来看看输出了什么
来看我们的测试目录test的结构
1 2 3 4 5 6 7 8 9 10 11 12 13 | test
├── a
│ ├── a
│ ├── b
│ └── c
│ └── file.md
├── b
│ ├── a
│ └── b
│ └── target.py
├── c
│ └── a
└── d
|
测试,进入test目录并使用os.getcwd()返回当前路径:
1 | >>> search(os.getcwd()) |
输出结果
1 2 3 4 5 6 7 8 9 10 11 12 | /home/Jkob/Github/test/b/b/target.py /home/Jkob/Github/test/b/b /home/Jkob/Github/test/b/a /home/Jkob/Github/test/b /home/Jkob/Github/test/a/b /home/Jkob/Github/test/a/a /home/Jkob/Github/test/a/c/file.md /home/Jkob/Github/test/a/c /home/Jkob/Github/test/a /home/Jkob/Github/test/d /home/Jkob/Github/test/c/a /home/Jkob/Github/test/c |
目录的遍历有什么用呢,我们可以添加条件来(搜索/操作)目录下所有符合条件的文件
文件名搜索
我们来对刚刚的函数进行简单的修改
1 2 3 4 5 6 7 8 | def search(path,keyword): content= os.listdir(path) for each in content: each_path = path+os.sep+each if filename in each: print(each_path) if os.path.isdir(each_path): search(each_path,keyword) |
与刚刚不同的只有简单几行
- 第1行:函数参数增加了要搜索的文件名
- 第5,6行:增加了判断,我们这里使用‘in’ 而不是‘==’ 的目的是为了使用模糊匹配,只要包含搜索的关键字就符合条件 -第8行:由于我们整个函数没有修改filename,所以我们可以将搜索条件传递下去
我们这次再来测试,寻找藏起来的target.py
1 | >>>search(os.getcwd(),'target') |
结果
1 | /home/Jkob/Github/test/b/b/target.py |
再试一次
1 | >>>search(os.getcwd(),'tar') |
结果
1 | /home/Jkob/Github/test/b/b/target.py |
文件内容搜索
然而只有文件名字符合并不能满足我们的需求,我们有时也需要查找文件里面的内容是否符合关键字需求
1 2 3 4 5 6 7 8 | def content_search(filepath,keyword): f = open(filepath,'r') for line in f: if keyword in line: f.close() return True f.close() return False |
在这里我们定义了一个函数content_search(),搜索文件内容并默认返回False,如果符合关键字条件即返回True并终端该项搜索
别忘记关闭文件哦
接下来我们将这个函数整合到我们刚刚的文件搜索函数中
关键字搜索整合
我们来把刚才的内容搜索函数添加到我们刚才的搜索函数中
1 2 3 4 5 6 7 8 9 10 | def search(path,keyword): content= os.listdir(path) for each in content: each_path = path+os.sep+each if keyword in each: print(each_path) if os.path.isdir(each_path): search(each_path,keyword) elif content_search(each_path,keyword): print(each_path) |
我们只添加了最后两行,即当该文件包含关键字时,我们显示该文件路径。但是为什么我们不能把这个和刚才文件名判定条件放在一起呢?因为有的文件名指代的是文件夹,我们需要将其放在文件夹判断之后
我们来测试一下,其实目录下的file.md文件是编辑过的,内容为'target':
1 | search(os.getcwd(),'tar') |
返回 #!shell /home/Jkob/Github/test/b/b/target.py /home/Jkob/Github/test/a/c/file.md
如果我们将整个文件作为工具的话,我们可以最后一行添加
1 | search(os.getcwd(),input('Your Keyword:')) |
完整代码
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 | import os def search(path,keyword): content= os.listdir(path) for each in content: each_path = path+os.sep+each if keyword in each: print(each_path) if os.path.isdir(each_path): search(each_path,keyword) elif content_search(each_path,keyword): print(each_path) def content_search(filepath,keyword): f = open(filepath,'r') for line in f: if keyword in line: f.close() return True f.close() return False search(os.getcwd(),input('Your Keyword:')) |
示例:
1 2 3 4 | [Jkob@localhost test] $ python3 test.py Your Keyword:tar /home/Jkob/Github/test/b/b/target.py /home/Jkob/Github/test/a/c/file.md |