背景
一起回顾一个大家非常熟悉场景。
上周开发一个需求,开发过程中,我需要登录到服务器上看一下服务运行的日志,确认运行状态或者看一些debug的信息。所以我登录到跳板机,此时我发现我忘了某一台机器的具体名字(通常能记得的人都是天才),所以需要用跳板机提供的 autoget 命令来通过服务器组名来获得机器的列表。
此时我发现我连服务器组名都忘了,所以需要上 eagle eye 上查寻一下组名。这个查询可能得依靠我的记忆打出组名的前缀,通过 eagle eye 给出的补全提示列表来识别出其中那个我需要的组名。
终于我得到了我的组名,为了避免我下次再忘记而不得不再繁琐的查询一遍,我选择把这些结果记录到我的记事本中,方便我下次查找使用。终于我登录了机器,可是不巧我忘了日志记录的位置,我想起某个同事曾经告诉过我日志的路径,于是我查找了与那个同事的聊天记录,找到了这个日志路径。同样为了防止忘记,我又把它记录到了我的记事本中方便下次查找。然后我把日志路径复制粘贴到命令行,我终于可以开始工作了。
昨天我又开发了一个需求,我还需要登录到服务器上看一下服务运行的日志,确认运行状态或者看一些 debug 的信息。所以我登录到跳板机,需要用跳板机提供的 autoget 命令来通过服务器组名来获得机器的列表,我想起了我在记事本中记录了这个内容,于是我打开记事本,搜索了 keyword,在简单的翻找下,我找到了我想要的命令。
进入到机器后,我发现日志的路径我还是没有记住。于是,我再次打开记事本,搜索了另一个 keyword ,再次翻找了一下,找到路径后把它复制粘贴到命令行,我一边粘贴一边想,我要是像在本机的终端环境中,把这些命令写成 bashrc 中的 alias 就好了。我又可以开始工作了。
于是,我的记事本中的内容一般都是这样:
从上述两次流程的对比中,我们发现记事本已经给我们的工作带来很大的提效了。但是在昨天流程最后我的思考中,我们不难发现,这个提效,还有提升的空间。我认为任何用过 shell 的 alias 的同学都会认同我的观点:如果上述流程能用alias来记录这些冗长的命令,我们就不用麻烦记事本了不是吗?
可是跳板机是公共资源,有严格的使用规范。具体服务器又是容器化部署,每次部署都会是一个新的容器,所以在当前的bashrc上写下什么并没有用。或许我们能寻找一个新的途径来实现这个需求。
问题
让我们从背景中总结我们正在面临的是哪些问题:
1、工作中存在非常多冗长难记的信息,需要我们在各个场景反复输入。
2、这些冗长的信息来源分散,查找起来非常麻烦耗时。
每次需要输入时等要通过额外的操作,频繁切换聚焦的窗口来获取这些信息。
3、这些问题虽然各自都占用了我们为数不多的时间和精力,但因为场景小而频繁,当乘以次数后,这些消耗也变得非常可观,并且非常影响我们的工作体验。
思考
让我们思考一下当我们想要使用 alias 的时候我们实际想要的是什么?我以个人的经验来总结,大概是以下几点:
1、用一个很短的短词来替代一个需要高频输入的很长的句子。
2、用一个更好记的词替代一个难记易忘的句。
3、配置的成本可控,使用的成本很低。
我们品一品1、2两点,其本质就是一个字典,由短语为key,长句为value。这个是我们程序员的好朋友了,我们可以简单的通过一个文件就能实现这份配置。事实上,我们使用记事本记录,其实本质也是在使用字典的特性。而第三点,让我瞬间想到使用 Alfred 的 Workflow 这个Mac上的神器。关于 Alfred 此处不做介绍,不知道或者想要了解的同学可以移步官网。
设计
其实针对我们已经给出的需求,我们非常容易就可以得出一个设计思路。我们可以固定一个文件路径保存一个文件,这个文件以一种简单的格式或方式保存一个字典。编写一个 alfred 的 workflow 来解析这个文件形成一个 Map ,并通过搜索和匹配 key 来快速的获取 value ,而获取 value 最有效的方式就是把 value 输出到系统的剪切板中。
考虑到 Mac 和 Alfred 的使用用户并不全是工程师,我们选择记录字典的格式最好越简单越好。所以我计划以普通的文本格式,每一行为一个键值对,第一个空格前的短词为 key ,第一个空格后的内容为 value 。直接让用户新建指定路径的文件并通过编辑文件的方式来管理的形式确实可以被一部分用户所接受,但是为了能面对更多用户,我认为以 workflow 的方式在增删字典的内容也同时是需要支持的。这样不想关心具体实现、不愿接触文本文件的用户同样可以无感使用。
最后我给这个 workflow 取名为 EasyAlias。
实现
来看一下 workflow 的排版:
通过三个关键字的Alfred命令,分别实现设置alias(sal, set alias),删除alias(dal, delete alias),查找(gal, get alias)。
其中sal和dal使用简单的keyword输入,而gal为了使用Alfred通过的展示候选列表和搜索匹配的能力,而使用了Script Filter作为输入。三者都通过shell调用了一个实现主要功能的python脚本easy_alias.py,通过传入不同的action参数来区分行为。
sal:
python easy_alias.py set {query}
dal:
python easy_alias.py del {query}
gal:
python easy_alias.py show {query}
cat filter.output
easy_alias.py
# coding=utf8
import sys
import json
from os import listdir, makedirs
from os.path import isfile, join, exists, expanduser
base_path = expanduser("~/.easy_alias")
file_name = "alias_conf"
file_path = join(base_path, file_name)
alias_map = dict()
def init():
if not exists(base_path):
makedirs(base_path)
if not exists(file_path):
open(file_path, 'w').close()
def get_key_and_value(text):
seqs = text.strip().split(' ')
if len(seqs) < 2:
return None, None
key = seqs[0];
value = reduce(lambda x, y: x.strip() + ' ' + y.strip(), seqs[1:])
return key, value
def get_alias_map():
with open(file_path, 'r') as f:
for line in f.readlines():
k, v = get_key_and_value(line)
if k == None or v == None:
continue
alias_map[k] = v
def set_alias():
if len(sys.argv) < 3:
return
text = sys.argv[2].strip()
k, v = get_key_and_value(text)
if k == None or v == None:
return
alias_map[k] = v
def del_alias():
if len(sys.argv) < 3:
return
key = sys.argv[2].strip()
new_content = ""
if key in alias_map:
alias_map.pop(key)
def show_alias():
items = list()
for k, v in alias_map.iteritems():
d = {
"uid": k,
"type": "default",
"title": k,
"subtitle": v,
"arg": v,
"autocomplete": k,
"icon": {
"type": "fileticon",
"path": "icon.png"
}
}
items.append(d)
show = {"items": items}
with open('filter.output', 'w') as f:
f.write(json.dumps(show))
def write_map_to_file():
file_content = ''
for k, v in alias_map.iteritems():
file_content += k + ' ' + v + '\n'
with open(file_path, 'w') as f:
f.write(file_content)
if __name__ == '__main__':
init()
get_alias_map()
action = sys.argv[1]
with open(join(base_path, 'logs'), 'a') as f:
f.write(str(sys.argv) + '\n')
if (action == 'set'):
set_alias()
if (action == 'del'):
del_alias()
if (action == 'show'):
show_alias()
write_map_to_file()
效果
设置一个alias
查找一个alias
删除一个alias
如果觉得通过sal设置和dal删除的方式太麻烦,也可以直接编辑~/.easy_alias/alias_conf
保存文件再查询
作业
这个 workflow 本身很简单很好实现。本文也希望不仅仅只是一个简单分享,希望能与读者有所互动,所以打算留个回家作业。
可以发现现在 dal 命令现在需要使用者盲打key,而不是像gal这样可以搜索补全。这会给使用者带来一定烦恼。回家作业就是将 dal 命令也改造成像 gal 一样可以搜索补全的形式。
总结
让我们回过头看一下我们再开始时面对的问题是否得到了很好的解决。
我们无法改变工作中频繁需要冗长信息的状况,但是我们通过访问剪切板的方式让输入变得简单。
我们用一个文件将这些信息集中在一起,并且通过工具打打提升了我们检索这些信息的效率。
Alfred提供给我们一个在检索并获取这些信息上无需切换窗口,并且操作非常简单的方式。
很高兴,我们很大程度上解决了我们先前提出的这些问题!
最后
今天我又开发了一个需求,我还需要登录到服务器上看一下服务运行的日志,确认运行状态或者看一些debug的信息。所以我登录到跳板机,唤醒了Alfred,输入gal ahostp,并将结果粘贴在命令行获得了机器列表。登上机器后,我再次唤醒Alfred,输入gal alog,并粘贴在命令行中。现在我可以开始工作了。
关注「淘系技术」微信公众号,一个有温度有内容的技术社区~