1. 程式人生 > >Python自定製tail命令,tail -f 功能小解

Python自定製tail命令,tail -f 功能小解

首先附上效果圖

這是在我的伺服器上執行結果。假設我希望之檢視220.184.92....的一些資訊 python tail.py -grep220.184.92.127就可以了

因為做Java後端的,所以總需要檢視log日誌,我不知道別人有啥好的方法檢視,我是使用tail -100f   ./xxxx.log,呼叫介面然後趕緊在shell中Ctrl+c,然後在翻過去找,覺得有點累

想著改造下,把tail的整個原始碼下載下來了tail原始碼,開始想著直接在tail.c裡面直接修改.

然後我做了一件很無聊的事情- -。。。

其實我想要的只有tail這個命令的-f選項這個功能,沒必要去寫c,現成的庫相對其他的來說太少了,還要連結修改Makefile,於是我想到了讓C去呼叫Python庫,修改了Makefile,

想著還得拖著一個py檔案,更噁心了。

索性我直接用Python寫一個tail -f + 關鍵字上色的功能算了

那麼tail -f 的時候當有新的資料寫入的時候是怎麼做到不斷追加列印的呢?

檢視 tail.c檔案

我在檔案中找到如下

這個地方有個forever  = 1,這個標誌是一個static的標誌,他代表這個檔案將不會退出,而是當有新的內容新增進來後繼續列印。

當然因為tail命令支援多個檔案的同時輸出,所以他使用一個結構體對檔案進行維護,這個結構體中維護了一些其中一個檔案的一些資訊如:

檔名,檔案描述符,檔案偏移量,磁碟,iNode等一些資訊

正是因為有了這些資訊我們可以不關心檔案是否被改名,檔案有新的資料寫入時候繼續向下讀取列印,這些能力。

在程式挨個開啟檔案後,在tail_file中執行一次全部的列印,具體列印數量按照給定的n_units來給定

在tail.c的main函式中有如下程式碼


他表示當有新的內容出現的時候回打印出來。

然而在tail_file在中其實只是執行一個很簡單檔案讀取列印,在也沒有其他的了.注意這裡並不關閉檔案描述符。因為在後面的forever處還可能用到。

進入tail_forever這個函式中去,頭幾行我就看到了一個while關鍵字,剩下的我認為沒有必要再繼續分析下去了,倒此所有關於tail -f命令的實現原理全部get到了。

綜上:

tail -f 這個功能原理其實就是用一個while打開了一個檔案並將檔案內容全部輸出,然後一直在不停的嘗試去讀取這個檔案,當有新的內容寫入這個檔案的時候繼續讀取並輸出。

那麼我們只需要在檔案列印前將檔案處理了即可

而文書處理這是Python的強項。附上Python實現 tail -f 功能關鍵字搜尋過濾的全部Python程式碼,不足之處望斧正。

import sys
path = sys.argv[1] 
tar = None

try:
    tar = sys.argv[2]
    print '>>>>>' + tar
except:
    tar = None

class tail_py_grep:
    def __init__(self, path, tar):
       self.tar = tar 
       self.path = path
#去掉指令
    def grep(self):
        if self.tar is None:
            return 
        self.tar = self.tar.lstrip('-grep')
#關鍵字上色
    def setColor(self, colorStr):
        perfix = '\033[1;35m'
        suffix = '\033[0m'
        return perfix + colorStr + suffix

    def find(self, string):
        if self.tar is None:
            return string
        num = 0
        while True:
            pos = string.find(self.tar)
            if -1 == pos:
                break
            string = string.replace(self.tar, 's%s%s')
            num += 1
        replace_string = self.setColor(self.tar)
        return string.replace('s%s%s', replace_string, num) 

    def tail_grep(self):
        self.grep()
        with open(self.path, 'r') as f:
            num = 0
            while True:
                for i in f.readlines():
                    num += 1
                    snum = self.setColor('[' + str(num) + '] ')
                    print snum + self.find(i.replace('\n', ''))

if __name__ == '__main__':
    gp = tail_py_grep(path, tar)
    gp.tail_grep()
一個比較簡單的小程式碼,等有時間了我會拆分模組,新增正則匹配和多關鍵字匹配,將匹配處抽取出來。記錄一下。