终端搜索工具

做人嘛,开心就好了

为了避免遗忘,先附上repo链接,有兴趣的拿去用咯。

https://github.com/guoruibiao/worktools/tree/master/searcher

前言

平时都是在终端下进行开发,文件少代码量不大的时候,查找某些方法也好,关键字也罢,都还可以,不算费时。但是随着代码量的不断增加,项目越写越大,很多文件,方法就根本找不到到底在哪个地方了。这个时候再去一个一个的找的话,就不好玩了。

也许你会说,我有IDE,全局搜索下不就好了,干嘛这么费事咧。是的,IDE有其独特的优点。但是完全在终端下工作,就用不了纯粹的IDE了。VIM中有一个插件,叫ctrlp。在normal模式下按下Ctrl+P键,就可以查找本级目录(以及子目录)下包含有输入的关键字的文件了。如下图。


VIM插件Ctrlp的文件查询效果

相信你也能看出来了,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
做人嘛,开心就好了
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 206,839评论 6 482
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 88,543评论 2 382
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 153,116评论 0 344
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 55,371评论 1 279
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 64,384评论 5 374
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,111评论 1 285
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,416评论 3 400
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,053评论 0 259
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 43,558评论 1 300
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,007评论 2 325
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,117评论 1 334
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,756评论 4 324
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,324评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,315评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,539评论 1 262
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,578评论 2 355
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,877评论 2 345

推荐阅读更多精彩内容

  • Ubuntu的发音 Ubuntu,源于非洲祖鲁人和科萨人的语言,发作 oo-boon-too 的音。了解发音是有意...
    萤火虫de梦阅读 99,159评论 9 467
  • Android 自定义View的各种姿势1 Activity的显示之ViewRootImpl详解 Activity...
    passiontim阅读 171,517评论 25 707
  • linux资料总章2.1 1.0写的不好抱歉 但是2.0已经改了很多 但是错误还是无法避免 以后资料会慢慢更新 大...
    数据革命阅读 12,135评论 2 34
  • 【手写爱情绘本8.0】行走在红尘里,每个人都会遇见暴风骤雨和诗情画意。当岁月的帷幕徐徐拉开,俗世中的每个人都成了人...
    主播亚东阅读 217评论 0 1
  • 行动的意义不是为了别人的认可,而是你获得了什么。 今天,行动营结营了,我除了做到了全勤,其他什么都没有。如果说没有...
    成长的温度阅读 552评论 0 2