AWK(簡易的文本處理腳本語言)入門學習

前言

由於最近的工作內容的關係, 經常需要對文本文件做一些處理. 每次都要寫個腳本來處理實在是有點麻煩. 這時候想起來很久以前稍微接觸過的AWK, 來做這個工作真的是再合適不過了.

因此, 趁着這個機會, 把AWK深入學習一點,記錄在此.

概述

AWK是一門解釋型的編程語言。在文本處理領域它是非常強大的,它的名字來源於它的三位作者的姓氏:Alfred Aho, Peter Weinberger 和 Brian Kernighan。

GNU/Linux發佈的AWK目前由自由軟件基金會(FSF)進行開發和維護,通常也稱它爲 GNU AWK。

awk在下列任務中都有非常不錯的發揮, 本文後續也會舉很多示例.

  • 文本處理
  • 輸出格式化的文本報表
  • 執行算數運算
  • 執行字符串操作等等

簡單來說awk就是把文件逐行的讀入,以空格爲默認分隔符將每行切片,切開的部分再進行各種分析處理。

你可以將其理解爲一個linux命令,只是使用參數以及方法多樣一些. 因爲我們經常會在命令行直接使用它.

你也可以將其理解爲一個簡易的腳本語言, 因爲在使用過程中我們也可以寫邏輯表達式等各種語句.

先來個熱場的示例.

已有一個文本文件,格式如下:

前面的數字是熱度, 後面的字符串是搜索詞.

100 阿里巴巴
200 京東
300 淘寶
400 awk怎麼使用

我們想計算, 熱度大於等300的詞的熱度, 在總熱度中的一個比例

雖然聽起來有點繞, 但是這是一個非常常見的需求, 對應到這個示例中我們是想計算 (300 + 400 ) / ( 100 + 200 + 300 + 400), 此時我們只能打開我們的編譯器, 選擇一門語言之後開始寫代碼了. 其實不用.

把上面的文本內容放進 a.txt中,然後執行下面的shell命令即可, 你會看到預期之中的 0.7.

awk '{{if ($1 >= 300) {sub_sum +=$1}};sum += $1 }; END{ret = sub_sum * 1.0 / sum; print ret}' a.txt

這段腳本做了什麼事情呢?

  1. 遍歷每一行,按照空格爲分隔符切割.
  2. 維護兩個變量, 每一行都將第一列的數字累加到sum. 如果數字大於等於300,則將他累加到 sub_sum.
  3. 在執行結束後, 將 sub_sum和sum做一個除法.

怎麼樣, 是不是比寫其他shell或者python腳本快多了?

接下來將進入學習時間, 我們逐個知識點的學習,看完本文,你也能這麼花裏胡哨的解決文本處理問題~.

基礎語法

腳本語法

awk除了可以在命令行執行之外, 還可以寫成腳本文件進行執行.我們大致的瞭解一下這個用法,之後不做詳細講解,以命令行用法爲主要內容. 因爲文本的用戶和命令行大同小異.

首先,創建一個包含腳本內容的文本文件 test.awk

{print $1 } 

然後我們用命令行執行這個腳本文件.

 awk -f command.awk marks.txt

這個其實是相當於命令行直接執行的一個擴展, 當你寫的腳本十分複雜(不推薦),且需要多人合作或者共享的時候, 腳本文件會是一個不錯的選擇.

命令行語法

awk [options] file ...

把上面腳本文件語法中的內容寫到 options 即可.


上面所講的, 是 awk是什麼以及 怎麼在系統中使用awk,接下來的內容就是 awk自身的一些語法.

程序結構

awk程序的思路是, 逐行處理一個文件.

那麼讓我們想一下, 當我們想要 處理一個文件的時候會需要做些什麼?

  1. 進行處理之前, 先初始化一些信息.
  2. 逐行處理文本, 記錄一些信息.
  3. 處理完之後,進行一些信息整理.比如打印,重定向等.

awk的程序結構也是如此.

BEGIN 語句塊

BEGIN {awk-commands}

BEGIN語句塊在程序開始的使用執行,它只執行一次,在這裏可以初始化變量。BEGIN是AWK的關鍵字,因此它必須爲大寫,注意,這個語句塊是可選的。

BODY 語句塊

/pattern/ {awk-commands}

BODY語句塊中的命令會對輸入的每一行執行,我們也可以通過提供模式來控制這種行爲。注意,BODY語句塊沒有關鍵字。

END 語句塊

END {awk-commands}

END語句塊在程序的最後執行,END是AWK的關鍵字,因此必須爲大寫,它也是可選的。

所以一個添加了全部可選項的awk命令如下所示:

awk [options] 'BEGIN{};{};END{}' file.txt

操作符

awk對常用的操作符都有支持,且與c語言使用方法一樣.具體支持的操作符有:

  • 算數操作符
  • 增減運算符
  • 自增自減操作符
  • 賦值操作符
  • 關係操作符
  • 邏輯操作符
  • 三元操作符
  • 一元操作符
  • 指數操作符
  • 字符串連接操作符
  • 正則表達式操作符

流程控制

awk支持流程控制, 比如在本文最前方的示例中我們使用了if語句.

或者類似下面的if語句都是合法的.

awk 'BEGIN {
   a = 30;
   
   if (a==10)
   print "a = 10";
   else if (a == 20)
   print "a = 20";
   else if (a == 30)
   print "a = 30";
}'

循環

循環操作與其他C系語言一樣,主要包括 for,whlie,do…while,break,continue 語句.

示例:

awk 'BEGIN {
   sum = 0; for (i = 0; i < 20; ++i) {
      sum += i; if (sum > 50) exit(10); else print "Sum =", sum 
   } 
}

內建變量

  • 0 表示正在處理的當前行
  • 1 表示當前行的第一列, 以此類推, 2表示第二列…
  • NR 表示文件中的行號,表示當前是第幾行
  • NF 表示文件中的當前行被分割的列數,可以理解爲 MySQL 數據表裏面每一條記錄有多少個字段,所以 NF 表示倒數第一格字段, (NF-1) 表示倒數第二個字段.
  • FS 表示 awk 的輸入分隔符,默認分隔符爲空格和製表符,可以對其進行自定義設置
  • OFS 表示 awk 的輸出分隔符,默認爲空格,也可以對其進行自定義設置
  • FILENAME 表示當前文件的文件名稱,如果同時處理多個文件,它也表示當前文件名稱
  • RS 行分隔符,用於分割行,默認爲換行符
  • ORS 輸出記錄的分隔符,默認爲換行符

內建函數

與內建變量相對應的, 也有一部分的內建函數.

awk 還提供了一些內置函數,比如:

  • toupper() 用於將字符轉爲大寫
  • tolower() 將字符轉爲小寫
  • length() 長度
  • substr() 子字符串
  • sin() 正弦
  • cos() 餘弦
  • sqrt() 平方根
  • rand() 隨機數

內建函數還有一些其他的, 具體可以在使用時在 man awk中查詢.

自定義函數

雖然我個人是不支持用awk來做這麼繁雜的編程工作的,但是awk支持我們自定義函數並且調用. 語法規範如下:

function function_name(argument1, argument2, ...) { 
   function body
}

我們可以在一個awk腳本中放入一下內容, 然後執行它.

function main(){
   print "function"
}

BEGIN {
   main()
}

常用場景示例

這裏會列出一些常用的,簡單的使用示例.

所有的示例都以下面的示例爲輸入進行運行.

1) Amit    Physics        80
2) Rahul    Maths        90
3) Shyam    Biology        87
4) Kedar    English        85
5) Hari    History        89

打印某列或者字段
AWK可以只打印輸入字段中的某些列。

$ awk '{print $3 "\t" $4}' marks.txt
Physics    80
Maths    90
Biology    87
English    85
History    89

在示例文本中,第三列包含了科目名,第四列則是得分,上面的例子中,我們只打印出了這兩列,$3 和 $4 代表了輸入記錄中的第三和第四個字段。

打印所有的行
默認情況下,AWK會打印出所有匹配模式的行

$ awk '/a/ {print $0}' marks.txt
2)  Rahul   Maths    90
3)  Shyam   Biology  87
4)  Kedar   English  85
5)  Hari    History  89

上述命令會判斷每一行中是否包含a,如果包含則打印該行,如果BODY部分缺失則默認會執行打印,因此,上述命令和下面這個是等價的

$ awk '/a/' marks.txt

打印匹配模式的列
當模式匹配成功時,默認情況下AWK會打印該行,但是也可以讓它只打印指定的字段。例如,下面的例子中,只會打印出匹配模式的第三和第四個字段。

$ awk '/a/ {print $3 "\t" $4}' marks.txt
Maths    90
Biology    87
English    85
History    89

任意順序打印列

$ awk '/a/ {print $4 "\t" $3}' marks.txt
90    Maths
87    Biology
85    English
89    History

統計匹配模式的行數

$ awk '/a/{++cnt} END {print "Count = ", cnt}' marks.txt
Count =  4

打印超過18個字符的行

$ awk 'length($0) > 18' marks.txt
3) Shyam   Biology   87
4) Kedar   English   85

查找history歷史中,最常用的10個命令

history | awk '{a[$2]++}END{for(i in a){print a[i] " " i}}' | sort -rn | head

過濾文件中重複行

awk '!x[$0]++' <file>

將一行長度超過 72 字符的行打印

awk 'length>72' file

查看最近哪些用戶使用系統

last | grep -v "^$" | awk '{ print $1 }' | sort -nr | uniq -c

計算文本中的數值的和

awk '{s+=$1} ENG {printf "%.0f", s}' /path/to/file

快速幫助

當你用的時候臨時有忘記的或者不確定的,隨時可以查看幫助命令.

man awk

參考文章


完。







ChangeLog

2019-12-05 完成

以上皆爲個人所思所得,如有錯誤歡迎評論區指正。

歡迎轉載,煩請署名並保留原文鏈接。

聯繫郵箱:[email protected]

更多學習筆記見個人博客或關注微信公衆號 <呼延十 >------>呼延十

發佈了94 篇原創文章 · 獲贊 12 · 訪問量 5萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章