開發與維運

macOS 神器 Workflow ,讓效率翻倍!

滾動.gif

背景

一起回顧一個大家非常熟悉場景。

上週開發一個需求,開發過程中,我需要登錄到服務器上看一下服務運行的日誌,確認運行狀態或者看一些debug的信息。所以我登錄到跳板機,此時我發現我忘了某一臺機器的具體名字(通常能記得的人都是天才),所以需要用跳板機提供的 autoget 命令來通過服務器組名來獲得機器的列表。

此時我發現我連服務器組名都忘了,所以需要上 eagle eye 上查尋一下組名。這個查詢可能得依靠我的記憶打出組名的前綴,通過 eagle eye 給出的補全提示列表來識別出其中那個我需要的組名。

終於我得到了我的組名,為了避免我下次再忘記而不得不再繁瑣的查詢一遍,我選擇把這些結果記錄到我的記事本中,方便我下次查找使用。終於我登錄了機器,可是不巧我忘了日誌記錄的位置,我想起某個同事曾經告訴過我日誌的路徑,於是我查找了與那個同事的聊天記錄,找到了這個日誌路徑。同樣為了防止忘記,我又把它記錄到了我的記事本中方便下次查找。然後我把日誌路徑複製粘貼到命令行,我終於可以開始工作了。

昨天我又開發了一個需求,我還需要登錄到服務器上看一下服務運行的日誌,確認運行狀態或者看一些 debug 的信息。所以我登錄到跳板機,需要用跳板機提供的 autoget 命令來通過服務器組名來獲得機器的列表,我想起了我在記事本中記錄了這個內容,於是我打開記事本,搜索了 keyword,在簡單的翻找下,我找到了我想要的命令。

進入到機器後,我發現日誌的路徑我還是沒有記住。於是,我再次打開記事本,搜索了另一個 keyword ,再次翻找了一下,找到路徑後把它複製粘貼到命令行,我一邊粘貼一邊想,我要是像在本機的終端環境中,把這些命令寫成 bashrc 中的 alias 就好了。我又可以開始工作了。

於是,我的記事本中的內容一般都是這樣:

image.png

從上述兩次流程的對比中,我們發現記事本已經給我們的工作帶來很大的提效了。但是在昨天流程最後我的思考中,我們不難發現,這個提效,還有提升的空間。我認為任何用過 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 的排版:

image.png

通過三個關鍵字的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

image.png

查找一個alias

image.png

刪除一個alias

image.png

如果覺得通過sal設置和dal刪除的方式太麻煩,也可以直接編輯~/.easy_alias/alias_conf

image.png

保存文件再查詢

image.png

作業

這個 workflow 本身很簡單很好實現。本文也希望不僅僅只是一個簡單分享,希望能與讀者有所互動,所以打算留個回家作業。

可以發現現在 dal 命令現在需要使用者盲打key,而不是像gal這樣可以搜索補全。這會給使用者帶來一定煩惱。回家作業就是將 dal 命令也改造成像 gal 一樣可以搜索補全的形式。

作業下載
EasyAliasPro

總結

讓我們回過頭看一下我們再開始時面對的問題是否得到了很好的解決。

我們無法改變工作中頻繁需要冗長信息的狀況,但是我們通過訪問剪切板的方式讓輸入變得簡單。
我們用一個文件將這些信息集中在一起,並且通過工具打打提升了我們檢索這些信息的效率。
Alfred提供給我們一個在檢索並獲取這些信息上無需切換窗口,並且操作非常簡單的方式。

很高興,我們很大程度上解決了我們先前提出的這些問題!

最後

今天我又開發了一個需求,我還需要登錄到服務器上看一下服務運行的日誌,確認運行狀態或者看一些debug的信息。所以我登錄到跳板機,喚醒了Alfred,輸入gal ahostp,並將結果粘貼在命令行獲得了機器列表。登上機器後,我再次喚醒Alfred,輸入gal alog,並粘貼在命令行中。現在我可以開始工作了。

關注「淘系技術」微信公眾號,一個有溫度有內容的技術社區~

image.png

Leave a Reply

Your email address will not be published. Required fields are marked *