登入  |  English
感謝您對「自由軟體鑄造場」的支持與愛護,十多年來「自由軟體鑄造場」受中央研究院支持,並在資訊科學研究所以及資訊科技創新研究中心執行,現已完成階段性的任務。 原網站預計持續維運至 2021年底,網站內容基本上不會再更動。本網站由 Denny Huang 備份封存。
也紀念我們永遠的朋友 李士傑先生(Shih-Chieh Ilya Li)。
源碼秘技 如何在 Linux 與 GnuCash 上使用 Awk 進行文字搜尋與排序

如何在 Linux 與 GnuCash 上使用 Awk 進行文字搜尋與排序

awk 是一套用以處理文字檔案的優秀 Unix 腳本語言,在多數 Linux 散佈套件中的版本是簡稱為 gawk 的 GNU awk。awk 將檔案中的每一行視為個別的記錄,一行中的每一個項目則是個別的欄位。如此一來就可以用各種彈性的方式處理你的檔案。經典的方式是以 /etc/passwd 來作說明,以下範例會輸出該檔案所有內容:

$ awk '{ print $0 }' /etc/passwd 
root:x:0:0:root:/root:/bin/bash
daemon:x:1:1:daemon:/usr/sbin:/bin/sh
bin:x:2:2:bin:/bin:/bin/sh
sys:x:3:3:sys:/dev:/bin/sh

不帶參數的 print 指令表示輸出一整行,$0 意思也是一整行,所以忽略 $0 同樣會得到一樣結果。假設你現在只想要用戶名稱與 UID 列表:由於 /etc/passwd 的資料欄位是以冒號分隔,因此很適合用 awk 來解析。你只需要從左邊從 1 開始數到你想輸出的欄位,然後像這樣截取出用戶名稱與 UID:

$ awk -F":" '{ print $1 " " $3 }' /etc/passwd 
root 0
daemon 1
bin 2
sys 3

-F 用來定義欄位分隔字元," " 則插入空白。想要先列出 UID?簡單,交換變數順序即可:

$ awk -F":" '{ print $3 " " $1 }' /etc/passwd

現在讓我們看看運用 awk 把一大堆財務數據匯入 GnuCash 的實際例子。

GnuCash 是自由與開放源碼軟體中的瑰寶之一,是一套執行於 Linux、Mac、Windows 的強大會計軟體。你可以匯入 QIF 與 OFX 檔案,不過說來可惜,儘管 CSV 是財務資料匯出匯入的通用格式,許多財務應用軟體都支援 CSV 匯出入,GnuCash 對 CSV 匯入卻僅提供部份支援。

假設你有一個包含歷年財務資料的龐大試算表,你希望將資料放進適當的會計軟體中,或是你想要把資料從某個會計軟體,匯入到 GnuCash 之中,但該軟體僅支援 CSV 匯出。你可以選擇重新鍵入所有資料,或是讓你的 Linux 腳本語言技術派上用場。流程是先產生 CSV 檔案,然後轉成 QIF 格式,再將 QIF 檔案匯入 GnuCash。GnuCash 對於 QIF 檔案正確性相當挑剔,因此得確保檔案內容無誤。

先確定複製一份你的原始檔案,不要破壞了原始檔案。

我會讓例子盡量簡單,僅使用以下的 QIF 欄位:

D - date
P - payee
M - memo
T - amount
N - check number, or any notation in the check number field
L - category, which corresponds to GnuCash accounts
^ - end of record

我們還需要在 QIF 檔頭中指定會計形態,如:

!Type:Bank  
!Type:Cash  
!Type:CCard  
!Type:Invst

QIF 規格支援更多項目,你可在 https://www.respmech.com/mym2qifw/qif_new.htm 找到完整列表。或者用 qif spec 作為關鍵字去查詢相關資料。

轉成 QIF 格式前,先確認你的 CSV 檔案格式是否正確。確認你的提款前有減號,例如 -33.72,而且不要使用錢字符號,存款前的加號可有可無,隨你喜歡。你的存提款必須在同一欄位。最後的 CSV 匯出檔案像這樣:

11/03/2008  Copy Junction  Copy of building codes	-33.72	8732  Supplies	
11/03/2008  Home Depot	Trowel	-17.05	8734  Tools	
11/03/2008  Dewalt Service Center	Charger for Drill  -75.85  8735	Tools	
11/04/2008  Building Supply  Margin trowel  -13.23  8736  Tools	
11/05/2008  Jane Smith   invoice #5843	8,500.00	   dep   income:contracting

如果 QIF 檔案中有任何錯誤,GnuCash 就無法成功匯入。我碰過的問題有,用了多個減號如 --33.72,額外的小數點,日期格式錯誤。awk 不會理會這些問題,但 GnuCash 會。準備好之後,將 CSV 檔案轉成 QIF 格式:

$ ( echo '!Type:Bank'; cat exportfile.csv | awk -F $'\t' '{ print "D" $1; print "P" $2; print "M" $3; print "T" $4; print "N" $5; print "L" $6; print "^"; }' ) > importfile.qif

結果像這樣,提款以減號表示,存款則無符號:

!Type:Bank
D03/25/2008
PJane Smith
M invoice #4657
T4000.00
Ndep
Lincome:contracting
^
D04/02/2008
PFirst Bank of Money
MCheck Order
T-21.44
NACH
Lbank fees
^
D05/15/2008
PPretty Designs
MDesign Services
T-500.00
N8922
LContract Services
^

注意到如何使用針對水平製表 \t 的 ASCII 跳脫序列,來指定以 tab 鍵作為欄位分隔符號。如果一切無誤,你會得到可匯入 GnuCash 的 QIF 檔案。

awk 在搜尋文字區塊上有著優秀能力,當 grep 沒辦法得到你想要的結果時,你可以試試 awk。例如,你想要從完整 lspci 輸出中找出特定設備:

$ lspci -v | awk '/VGA/,/^$/'
01:00.0 VGA compatible controller: NVIDIA Corporation G98 [GeForce 8400 GS] (rev a1) (prog-if 00 [VGA controller])
        Subsystem: Micro-Star International Co., Ltd. Device 1162
        Flags: bus master, fast devsel, latency 0, IRQ 18
        Memory at fd000000 (32-bit, non-prefetchable) [size=16M]
        Memory at d0000000 (64-bit, prefetchable) [size=256M]
        Memory at fa000000 (64-bit, non-prefetchable) [size=32M]
        I/O ports at dc00 [size=128]
        [virtual] Expansion ROM at fe9e0000 [disabled] [size=128K]
        Capabilities: 
        Kernel driver in use: nvidia
        Kernel modules: nvidia_current, nouveau, nvidiafb

插入符號 ^ 正規表示式的定位符,用來對應字串起始處,$ 則對應終止處。所以上例中 /^$/ 會找出文字區塊起始與終止處的斷行。這是從以空白區隔各個段落的大型設定檔案中,截取特定區塊的漂亮技巧,例如 sshd_config:

$ awk '/X11Forwarding/, /^$/' /etc/ssh/sshd_config 
X11Forwarding yes
X11DisplayOffset 10
PrintMotd no
PrintLastLog yes
TCPKeepAlive yes
#UseLogin no

我們經常使用 sort 與 uniq 指令,從檔案中找出並移除重複項目。不過如果你不希望你的原始檔被排序或更動,這時正是 awk 派上用場的時候,我們可以用 awk 截取不重複記錄並儲存在新的檔案中:

$ awk '!x[$0]++' filewithdupes > newfile

你的原始檔案原封不動,新檔案僅包含依序排列的不重複項目。

man awk 可以查到完整的選項說明,要發揮 awk 或任何 Unix/Linux 指令的大部份功能,你需要對正規表示式有不錯的理解。對此我推薦 Mastering Regular Expressions 這本書。如果你想挑最有用的東西來學,就學正規表示式吧,因為多數程式語言和 Linux/Unix 指令都用得到正規表示式。


原文網址:

  1. 如何在 Linux 與 GnuCash 上使用 Awk 進行文字搜尋與排序
    https://www.linux.com/learn/tutorials/724060-amazing-awk-fu-gnucash-import-find-blocks-of-text-remove-dupes-without-sorting/


您也許有興趣閱讀以下文章:




自由軟體鑄造場電子報 : 第 222 期 Sphinx - 用 reStructuredText 寫網站與書

分類: 源碼秘技



評論 

 
0 #1 alang 2013-07-16 10:43
感謝分享,這篇解決了我一個多年 的問題。