为了避免遗忘,先附上repo链接,有兴趣的拿去用咯。
https://github.com/guoruibiao/worktools/tree/master/searcher
前言
平时都是在终端下进行开发,文件少代码量不大的时候,查找某些方法也好,关键字也罢,都还可以,不算费时。但是随着代码量的不断增加,项目越写越大,很多文件,方法就根本找不到到底在哪个地方了。这个时候再去一个一个的找的话,就不好玩了。
也许你会说,我有IDE,全局搜索下不就好了,干嘛这么费事咧。是的,IDE有其独特的优点。但是完全在终端下工作,就用不了纯粹的IDE了。VIM中有一个插件,叫ctrlp。在normal模式下按下Ctrl+P键,就可以查找本级目录(以及子目录)下包含有输入的关键字的文件了。如下图。
相信你也能看出来了,ctrlp能找到的只是一个文件名,对于内部的变量还是心有余而力不足的。当然了,在VIM中其实也不是个事。各种插件工具,搞一搞,不输IDE。但是这和今天要写的工具的预期有点差距。我们要找到某个目录下包含某个方法,某个关键字的具体的位置。
在正式开始制作工具之前,下面需要先熟悉一下一些基础的东西。
查找
查找,基本上分为两块。一个是查找文件,一个是查找内容。
文件查找
最常用的文件查找命令是find。
find path -name "regex "
# 示例
➜ worktools git:(master) ✗ find ./ -name "*.p*"
.//searcher/colorcmd.pyc
.//searcher/searcher.py
.//searcher/colorcmd.py
.//sqlhelper/sqlhelper.py
.//sqlhelper/datatransfer.py
.//dingding/dingding.py
.//interfacetool.py
.//getrealip.py
.//detect-actions.py
.//getall/finder.py
.//getall/get.py
.//redis-analyzer/server.py
.//redis-analyzer/redishelper.py
.//redis-analyzer/__init__.py
.//redis-analyzer/__pycache__/redishelper.cpython-36.pyc
.//redis-analyzer/temp.py
可以看出find还会帮我们进行递归式的查找。
内容查找
实现内容查找的方式有很多方式,使用grep命令,或者使用Perl,Python,shell等脚本语言来做处理都是可以的。当然,不同的方式实现的最终效果也会有差距。
如果只是简单的想知道哪个文件包含了目标关键字,使用grep就可以了。
➜ worktools git:(master) ✗ grep 递归 searcher/searcher.py
# 明天做下递归版本
➜ worktools git:(master) ✗
但是如果想知道包含了关键字在(多个)文件中的行数,位置,这个时候在使用grep等命令就有点捉襟见肘了。但也不是说不能实现,如:
➜ worktools git:(master) ✗ find ./ -name "*.p*" | xargs grep 递归
.//searcher/searcher.py: # 明天做下递归版本
➜ worktools git:(master) ✗ find ./ -name "*.p*" | xargs grep hello
.//interfacetool.py:#cmd = "wget http://fanyi.badu.com/v2transapi?query=hello | python -m json.tool"
➜ worktools git:(master) ✗ find ./ -name "*.p*" | xargs grep coding
Binary file .//searcher/colorcmd.pyc matches
.//searcher/searcher.py:#coding: utf8
.//searcher/searcher.py:sys.setdefaultencoding("utf8")
.//searcher/colorcmd.py:# coding: utf8
.//searcher/colorcmd.py:sys.setdefaultencoding("utf8")
.//sqlhelper/sqlhelper.py:# coding: utf8
.//sqlhelper/datatransfer.py:# coding: utf8
.//sqlhelper/datatransfer.py:sys.setdefaultencoding('utf8')
.//dingding/dingding.py:# coding: utf8
.//interfacetool.py:# coding: utf8
.//getrealip.py:# coding: utf8
.//detect-actions.py:# coding: utf8
.//getall/finder.py:# coding: utf8
.//getall/get.py:# coding: utf8
.//redis-analyzer/server.py:# coding: utf8
.//redis-analyzer/server.py:sys.setdefaultencoding('utf8')
.//redis-analyzer/redishelper.py:# coding: utf8
.//redis-analyzer/__init__.py:# coding: utf8
.//redis-analyzer/temp.py:# coding: utf8
➜ worktools git:(master) ✗
而使用一些稍微高级一点的脚本语言,能实现的功能就会更多样化。比如高亮显示查找的关键字,添加行号元数据等等,这些使用高级语言,会更方便一点。
高亮工具
大二的时候接触的Python,一开始也是在命令行里面不断摸索这,从理解命令行参数的使用到自己封装了一个getpass2的库。什么进度条啊的都算是玩了下。在这么多的库中,有一个让我确实印象深刻。那就是colorama。一个可以让非黑即白的终端瞬间变得多姿多彩起来。
对我而言,colorama足够好用,但是init(autoreset=True)有时候并不能满足我的需求。比如我只想高亮某个关键字,需要操作的那就太多了。于是我打算自己写一个类似的,满足我的需求就好了,于是有了colorcmd。在正式写代码之前,还是要先理解下如何让终端输出多种颜色。
知识点普及
在支持真彩色的终端中,有这么一个约定。
ESC键的转移序列为ASCII码的\033.
变换颜色的格式如下:
\033[显示方式;前景色;背景色m
需要注意的是:显示方式,前景色,背景色至少存在一个就可以。如果存在多个,记得使用英文的分号进行分割。
显示方式有如下取值:
- 0 关闭所有效果
- 1 高亮
- 4 下划线
- 5 闪烁
- 7 反色
- 8 不可见
前景色以3开头,背景色以4开头。紧邻的为颜色取值,分别为:
- 0 黑色
- 1 红色
- 2 绿色
- 3 黄色
- 4 蓝色
- 5 紫色
- 6 青色
- 7 白色
简单的来测试下。
工具编写
这里我打算使用shell配合Python实现一个关键字高亮搜索的小工具。具体会有如下文件:
colorcmd.py 终端颜色样式工具类
searcher.py 关键字搜索
searcher.sh 文件搜索
searcher.sh
#!/usr/bin bash
# 使用shell配合Python脚本查找文件中某一个变量或者字符串所在的行数
filelist=`find $1 -name "*.*"`
for file in ${filelist[@]};do
#echo $file;
python /Users/changba164/guo/tools/worktools-master/worktools/searcher/searcher.py $file $2
done;
#find $1 -name "*.*" | xargs python $2
searcher.py
#!/usr/bin python
#coding: utf8
import sys
reload(sys)
sys.setdefaultencoding("utf8")
import re
import os
from colorcmd import Color, Style, Enhancer
def find(filepath, keyword):
if os.path.isdir(filepath):
# 明天做下递归版本
return []
result = []
with open(filepath, 'r') as file:
lines = file.readlines()
file.close()
# 遍历每一行,读取包含关键字的行,并进行临时存储,用于后续美化输出
counter = 0
for line in lines:
counter += 1
if keyword.lower() in line.lower():
wrappedword = Enhancer.mix(keyword, Color.BLACK_DEEPGREEN, Style.HIGHLIGHT+Style.UNDERLINE+Style.BLINK)
tmp = {"number": counter, "line":line.rstrip("\n").replace(keyword, wrappedword)}
result.append(tmp)
return result
def pretty_print(filepath, rows):
for row in rows:
if row is not None or row != []:
print "-------"*5 + filepath + "-------"*5
print "Line: {}\t {}".format(row['number'], row['line'])
filepath = sys.argv[1]
keyword = sys.argv[2]
rows = find(filepath, keyword)
pretty_print(filepath, rows)
colorcmd.py
#!/usr/bin python
# coding: utf8
import sys
reload(sys)
sys.setdefaultencoding("utf8")
"""
# 之前用过一个colorama的库,挺好用的,但是有一个缺点就是有时候init(autoreset=True)并不很好使,究其原因,还是设计层面的问题
于是我打算使用“包装”的思想,来做一个更好用一点的出来。
"""
class Color(object):
CLEAR = "\33[0m"
# 字体颜色 前景色
FORE_BLACK = "\33[30m"
FORE_RED = "\33[31m"
FORE_GREEN = "\33[32m"
FORE_YELLOW = "\33[33m"
FORE_BLUE = "\33[34m"
FORE_PURPLE = "\33[35m"
FORE_DEEPGREEN = "\33[36m"
FORE_WHITE = "\33[37m"
# 背景色
BACK_BLACK = "\33[40"
BACK_RED = BACK_DEEPRED = "\33[41m"
BACK_GREEN = "\33[42m"
BACK_YELLOW = "\33[43m"
BACK_BLUE = "\33[44m"
BACK_PURPLE = "\33[45m"
BACK_DEEPGREEN = "\33[46m"
BACK_WHITE = "\33[47m"
# 黑底彩色
BLACK_BLACK = "\33[90m"
BLACK_RED = BLACK_DEEPRED = "\33[91m"
BLACK_GREEN = "\33[92m"
BLACK_YELLOW = "\33[93m"
BLACK_BLUE = "\33[94m"
BLACK_PURPLE = "\33[95m"
BLACK_DEEPGREEN = "\33[96m"
BLACK_WHITE = "\33[97m"
"""
颜色相关工具类
"""
def __init__(self):
pass
class Style(object):
CLEAR = "\33[0m"
HIGHLIGHT = "\33[1m"
UNDERLINE = "\33[4m"
BLINK = "\33[5m"
REVERSE = "\33[7m"
BLANKING = "\33[8m"
"""
样式相关,前景色,背景色,加粗,下划线等
"""
def __init(self):
pass
class Enhancer(object):
"""
曾经有一个tag的交叉叠加,给了我这个思路。目标是做成一个无限叠加的增强品。
"""
def __init__(self):
pass
@staticmethod
def highlight(text="", color=Color.FORE_RED, style=Style.CLEAR):
return Style.HIGHLIGHT + style + color + text + Style.CLEAR
@staticmethod
def mix(text, color=Color.CLEAR, style=Style.CLEAR, highlight=False):
return style + color + text + Style.CLEAR
if __name__ == "__main__":
#print "\33[5m"+Color.FORE_GREEN+"Hello World!"+"\33[0m"
text = "郭璞"
print Enhancer.highlight(text, Color.BACK_GREEN, Style.BLINK)
print Enhancer.mix("what a amazing colorama!", Color.BLACK_PURPLE, Style.UNDERLINE+Style.HIGHLIGHT+Style.BLINK)
代码比较简单,但是还是有很大的拓展空间的。
比如以多线程的形式进行查找,这样速度会更加迅速。
终端输出的美化效果,现在就是个简单的输出了,如果有必要的话,可以借助PrettyTable这个库实现更优雅的输出效果。
如何使用
这个工具的入口是searcher.sh
,所以正常使用的话可以这么干:
sh ./searcher.sh targetpath keyword
# 示例
➜ searcher git:(master) ✗ sh searcher.sh ./ default
---------.//searcher.py------------
Line: 5 sys.setdefaultencoding("utf8")
---------.//colorcmd.py------------
Line: 5 sys.setdefaultencoding("utf8")
➜ searcher git:(master) ✗
但是这样每次都要输入一下sh命令 挺麻烦的。因此,放到alias里面就好多了。
vim ~/.zshrc (我的Mac安装了zsh,所以这里是~/.zshrc, 如果你用的是Linux,那么应该是~/.bashrc. 没有的话就新建一个。)
# 在最后面加上这么一行命令。
alias search='sh /absolute path/searcher.sh'
# 保存退出后还差一句命令,让别名的配置可以在当前的会话终端内生效。
source ~/.zshrc
完成后就可以很方便的在终端内搜索了。
格式如下:
search path keyword