程式設計雜筆

[資工雜筆] awk 簡單用法

其實以前有稍微使用過 unix 系統裡的 awk 來處理指令吐出來的結果,但都不是太難的組合,所以其實也不算真正了解,並能活用這個指令。今天剛好遇到一個蠻不錯的機會,可以把這東西完全學會,順便把這個過程記下來。

首先是文本的內容,大致上長這個樣子,亂碼指的是不要的東西

%$#!@%@%^$^%&#%^&#$^%&#^$&#%^&#^%
1th object: person
2th object: sky
3th object: building
4th object: truck
...
97th object: face
98th object: street
99th object: ramp
100th object: suitcase
...
%$#!@%@%^$^%&#%^
&#$^%&#^$&#%^&#^%

而目標是把所有的 object 後的東西都拿出來,然後以逗號分隔它。類似像這個樣子:

person,sky,building,truck,......,face,street,ramp,suitcase

其實這也不會太難,寫一個 python 程式,也是5行內解決,如下:

import re
with open('readme.txt') as file:
  text = file.read()
with open('category.txt', 'w') as file:
  file.write(','.join(re.findall('\dth object: (.*)\n', text)))

不過我們要自虐一點,用 awk 來寫,在 command line 解決,指令如下:

awk 'BEGIN{RS="\r\n"; ORS=""}/[0-9]th object:/{if($1 ~ /1th/){printf("%s", $4)}else{printf(",%s", $4)}}END{print "\n"}' readme.txt > category.txt

再把它詳細的結構拆一下,會長這個樣子:

awk '
BEGIN{
  RS="\r\n";
  ORS=""
}

/[0-9]th object:/{
  if($1 ~ /1th/){
    printf("%s", $4)
  } else {
    printf(",%s", $4)
  }
}

END{
  print "\n"
}' readme.txt > category.txt

回頭來看,程式碼總共分4個區塊,第一個區塊是 BEGIN。RS的意思指的是換行符號是 \r\n 。看到這裡,我想各位也可以猜出這個文本是在 Windows 系統上產生的。小小抱怨一下,我本來很理所當然的以為這個文本是在 Linux 上產生的,所以只給了一個\n,結果弄半天一直出錯==。ORS 則是 output 的換行符號,因為都要 output 在同一行,所以給空字串。

第二部分則是先用一個正規表示式去取得要的字串,成功取得了才會進入後方的區塊。如果 $1 是 1th 的話,那就不要有逗號在前(又是個種樹問題XDD),反之加個逗號。

最後,印出一個 \n,然後 redirect 到該去的地方。

雖然看上去比起 python 的做法好像也沒多聰明,沒錯,在這個問題的確是如此,但如果是處理很大的 csv 這種連 vim 開起來都很困難的結構化資料呢,亦或是處理 command line pipe 出來的結果呢,那可就不一定了。

廣告

對「[資工雜筆] awk 簡單用法」的一則回應

發表迴響

在下方填入你的資料或按右方圖示以社群網站登入:

WordPress.com 標誌

您的留言將使用 WordPress.com 帳號。 登出 /  變更 )

Google+ photo

您的留言將使用 Google+ 帳號。 登出 /  變更 )

Twitter picture

您的留言將使用 Twitter 帳號。 登出 /  變更 )

Facebook照片

您的留言將使用 Facebook 帳號。 登出 /  變更 )

連結到 %s