紀錄輸出訊息至 Excel

由於客戶會不定期得要求我們提供資料(俗稱ChangeNote)讓他們檢視目前專案進行的情況,其中最重要的一部分就是這段時間修改了哪些程式碼、修復了哪些Bug。雖然這些資料只需透過Git相關指令即可取得,但顯示在終端機的樣子實在不是很好看,還是要整理成表格才能交給客戶觀賞,因此泰勞就寫了一個簡單的Python腳本來幫我完成這件事!

參考資料:
https://github.com/python-excel/xlwt
Get the output of system command as a string in python - StackOverflow

網路上找到了一個很好用的模組-xlwt,可以用來將資料寫入Excel檔案。在使用它之前必須先透過以下指令來安裝。

$ pip install xlwt

可能有些人安裝時會遇到一些問題,如下圖所示。
通常看到Permission denied都會想到在指令前面加上sudo,確實是可以解決問題,但在我上網搜尋解答時,剛好看到一篇蠻重要的討論,作者建議不要使用sudo,取而代之的是在指令後面加上--user參數,如下所示。

$ pip install xlwt --user

安裝好xlwt之後就開始來寫Python腳本吧!先來練習將一些簡單的資料寫進一個Excel檔案,如下所示。

#!/usr/bin/env python

"""
Program:
This program will record log into Excel.
History:
20170707 Kuanlin Chen
"""


#匯入模組(Module)
import sys
import xlwt


#建立Workbook物件

book = xlwt.Workbook(encoding="utf-8")
#使用Workbook裡的add_sheet函式來建立Worksheet
sheet1 = book.add_sheet("Sheet1")

def main(orig_args):

    filename = "example.xls"
    output(filename)

def output(filename):

    #使用Worksheet裡的write函式將值寫入
    sheet1.write(0,0,'AAA')
    sheet1.write(0,1,'BBB')

    #將Workbook儲存為原生Excel格式的檔案
    book.save(filename)

if __name__ == '__main__':
    main(sys.argv)

接著執行此腳本就會出現一個名為example的Excel檔案,打開來會看到一個名為Sheet1的分頁,裡面存放了兩筆資料。
很簡單吧!接著嘗試將List裡面的值透過for迴圈依依寫入!

def output(filename):
    a = ['c', 'd', 'e', 'f', 'g']
    b = [123, 456, 789]
   
    i = 0
    for word in a:
        sheet1.write(i,0,word)
        i = i+1

    j = 0
    for num in b:
        sheet1.write(j,1,num)
        j = j+1

    book.save(filename)

此時表格裡面的第一行會是List a的資料,第二行會是List b的資料,如圖所示。
有沒有覺得很有趣呢?再來練習稍微複雜一點的,嘗試在腳本裡面執行一個簡單的指令,並且把輸出的訊息紀錄至檔案裡面。

#要多匯入這兩個Module
import subprocess
import string


def output(filename):
   
    proc = subprocess.Popen('ls',stdout=subprocess.PIPE)
    text = proc.stdout.read()
    print(text)  #除錯用

    text = text.split('\n')
    print(text) 
#除錯用
    i = 0
    for word in text:
        sheet1.write(i,0,word)
        i = i+1

    book.save(filename)

執行後會印出兩次text,主要目的為除錯,方便自己查看目前text物件的狀態。第一次印出來的是系統輸出的訊息的原始樣子,第二次印出的是經過換行符號來區分的List。
打鐵要趁熱打劫要趁三更半夜打Game要趁老闆不在打小孩要趁四下無人、打老婆......,不行打老婆(比司吉會變身)。總之,把指令的複雜度再稍微提高,把"ls"改成"ls -l",讓輸出的訊息更複雜一些。

def output(filename):
    

    #另一種方式
    #proc = subprocess.Popen('ls -l',shell=True,stdout=subprocess.PIPE)
    proc = subprocess.Popen(['ls','-l'],stdout=subprocess.PIPE)
    text = proc.stdout.read()

    text = text.split('\n')
    i = 0
    for line in text:
        #split方法若不帶入參數,會以空白部份分隔
        line = line.split()
        print(line)  #除錯用
        j = 0
        for word in line:
            sheet1.write(i,j,word)
            j = j+1
           
        i = i+1

    book.save(filename)

用巢狀迴圈讓輸出的訊息先以列為基準分開,再將每一列的內容以空白部份為基準分開,讓每一筆資料都單獨存放於一個欄位,使生成的表格更容易閱讀。
現在已經學會如何紀錄輸出訊息至Excel檔案了,回歸一開始的正題:將修改紀錄輸出至Excel檔案,就如同上面的方法,只要將欲執行的指令改成我要的,然後加入一些欄位標題即可生成一份[簡約]的ChangeNote!

另外,也許有些人會有這樣的需求,為了方便大家閱讀,某些文件會有固定的格式,所以需要將固定的格式匯入至新的檔案,再將資料依依寫入,這要怎麼做呢?此時只要使用兩個好用的模組-xlrdxlutils.copy即可達成上述條件,如下範例所示。

import sys
import xlwt
import xlrd
import xlutils.copy

try: 
    #將範本打開
    inbook = xlrd.open_workbook('sample.xls',     formatting_info=True)
    #複製給outbook物件
    outbook = xlutils.copy.copy(inbook)
    #取得分頁並將字串寫入座標為(5,5)的欄位
    #預設是不能複寫欄位裡的資料喔!
    outbook.get_sheet(0).write(5,5,"ILoveBaseball")
    #若儲存為同樣的檔名會出現Permission denied的錯誤訊息喔!
    outbook.save('mynote.xls')
except IOError:
    print('ERROR!')
    sys.exit('No such file: sample.xls')

註:
如果終端輸出的資料『長的很整齊』的話,就不需要搞的這麼複雜,因為CSV格式的檔案支援以逗號或空白分隔的資料,當選用Excel開啟副檔名為CSV的檔案,做些簡單的設定即可讓資料完美呈現喔,來看看下面的範例吧!

$ git log --oneline --pretty="%h,%s,%an" > example.csv

接著選用Excel開啟example.csv,並且選擇以逗號分隔,結果呈現如圖所示。
當然,直接將輸出放入CSV還是有些缺點的,像是它無法處理多行或有換行的字串,這會造成格式跑掉,也不能針對內容做修改或是調整欄位之類的需求。

GitHub:
https://github.com/Kuanlin-Chen/ChangeNote

留言

這個網誌中的熱門文章

程式語言常用之符號與詞彙 - 中英文對照

Repo 實用指令

什麼是 Bootloader?