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

前言

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

所以, 趁着這個機會, 把AWK深刻學習一點,記錄在此.linux

概述

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

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

awk在下列任務中都有很是不錯的發揮, 本文後續也會舉不少示例.編程

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

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

你能夠將其理解爲一個linux命令,只是使用參數以及方法多樣一些. 由於咱們常常會在命令行直接使用它.編程語言

你也能夠將其理解爲一個簡易的腳本語言, 由於在使用過程當中咱們也能夠寫邏輯表達式等各類語句.函數

先來個熱場的示例.學習

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

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

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 完成

以上皆爲我的所思所得,若有錯誤歡迎評論區指正。

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

聯繫郵箱:huyanshi2580@gmail.com

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

相關文章
相關標籤/搜索