為了避免遺忘,先附上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
複製程式碼