awk 入坑指北

awk(/ɔːk/) 是 *nix 下一種強大的文本處理工具,其名稱取自三位做者 Alfred Aho,Peter Jay Weinberger,Brian Wilson Kernighan。awk 提供的功能包括不只限於正則匹配、流控制、算術運算、甚至於函數等編程語言具有的一些特性。它發行於 1977 年,已經超過了 40 歲堪稱古董級軟件。爲了更讓人能直接明白它的用途,我把它稱爲是命令行下的 Excel,其中的一些概念和 Excel 有不少類似之處。linux

TR;DR

  • awk 是一種高效的文本處理工具。
  • awk 腳本的基本結構 BEGIN -> BODY -> END。
  • 基本語法,awk 腳本語法和 C 語言很不少類似之處。
  • awk 腳本編程實踐以及須要注意的地方。

基本用法

在 linux 環境下咱們有一些文本處理需求時,awk 就能派上用場了,好比 nginx 的訪問日誌,文本信息去重等等。awk 能夠直接在命令行中執行好比:nginx

echo "" | awk '{print "hello world!"}'

也能夠將一些邏輯比較複雜的代碼寫到一個 awk 腳本中,而後指定腳本文件執行:git

awk -f a.awk test.txt

程序結構

awk 直接在命令行中輸入和執行 awk 腳本效果是同樣的,因此如下代碼爲了便於閱讀都寫入到一個腳本文件中。
一個完整的 awk 腳本分爲三個部分:github

BEGIN{ print("BEGIN");  }
{ print("BODY");  }
END{ print("END");  }

可是 awk 腳本要能正確執行只須要其中一個階段就行,第一個階段是 BEGIN,就是還未開始掃描輸入文本時候的預處理時間,中間 BODY 是掃描文本執行階段,awk 每掃描到輸入文本一行數據就會執行 BODY 中的腳本代碼,最後是 END,即文本掃描完成的階段,在絕大部分使用場景中咱們直接在 {} 中寫代碼就能夠了,即省略掉了 BEGIN 和 END。編程

awk 理解輸入

前面已經提到,我將 awk 視爲 *nix 下的 Excel,下面提到的一些概念和 Excel 頗爲類似。對於 awk 處理的文本通常狀況下是一行一行的,好比 nginx 的日誌文件,在 awk 的視角文本的一行被視爲一條記錄(Record)行以 n 來進行劃分。在一行中經過空格又被分爲多個域(Field),這就和 Excel 的行列差很少了。因此在 awk 程序中存在 2 個全局變量 NF,NR,這就很容易理解了。數組

須要值得注意的是域的索引不是從 0 開始的,而是從 1 開始,0 是當前行的引用,經過 $n 的語法來拿到不一樣域的值。bash

{
    # 當前記錄有多少個域
    print("NF is:" NF);
    # 當前是第幾條記錄
    print("NR is:" NR);
    # 輸出當前行的文本
    print($0);
    # 輸出當前行的第一個域
    print($1);
}

以上代碼中 print 是 awk 的一個內置函數,用於輸出文本信息。在 awk 腳本中能夠經過 # 號來寫註釋。編程語言

awk 語法

和不少腳本程序同樣,awk 沒有嚴格的數據類型,不一樣數據類型直接能夠直接轉換。在 awk 中聲明的變量通通會成爲全局變量,因此在一處修改了變量值,腳本其餘地方也會受到影響。在流程控制上幾乎和主流編程語言徹底同樣。if-else, while 都是支持的,在後續的列子中能夠看到。函數

傳入參數

在命令行下經過 -v 參數還能夠給 awk 腳本傳入參數,好比:工具

echo '' | awk -v name="jiavan" '{print("hello, "name);}'

內置函數

awk 內置了不少字符串處理以及數學運算方面的函數,經常使用的如:

  • index(str1, str2):返回 str2 在 str1 中出現的索引。
  • length(str):返回一個字符串的長度。
  • substr(str, n, m):截取字符串 str 的子串。
  • match(str, reg):正則匹配,返回第一次匹配索引。

.....
跟多使用能夠 man 一下。

內置變量

awk 還內置了一些變量名:

$0            當前處理記錄
$1-$n         當前記錄的n個字段
FS            域分隔符
NF            當前記錄的域數目
NR            已經處理的記錄條數
RS            記錄分隔符
OFS           輸出字段分隔符
ORS           輸出記錄分隔符
ARGC          命令行參數個數
ARGV          命令行參數數組
FILENAME      當前輸入文件名字
IGNRECASE     記錄爲真表明忽略大小寫匹配
ARGIND        當前被處理文件的ARGV標誌符
CONVFMT       數字轉換格式 %.6g
ENVIRON       UNIX環境變量
ERRNO         UNIX系統錯誤消息
FIELDWIDTHS   輸入字段寬度的空白分隔字符串
FNR           當前記錄數
OFMT          數字的輸出格式 %.6g
RSTART        被匹配函數匹配的字符串首
RLENGTH       匹配函數匹配的字符串長度
SUBSEP        \034
PROCINFO      當前運行程序進程信息數組

awk 實踐

文本去重

有如下具備重複文本的文件 name.txt。

// name.txt
jiavan
kellen
lzy
fakafang
jiavan
lzy
pig

// a.awk
{
    ++names[$1];
}
END {
    for (key in names) {
        print(key) > "./unique.txt";
    }
}

上方 a.awk 先遍歷文件行存入一個數組,在 awk 中數組的 key 能夠是任意數據類型,value 也能夠是任意數據類型,名稱每出現一次 +1,最後就能統計出每一個名稱出現的次數以及將全部不重複的 key 輸出到一個文件中,這裏的操做和 bash 相似。

搜尋字符串

對於輸入的文本 words.txt,咱們使用 awk 找出帶有 av 關鍵字的單詞。

// words.txt
this is a test file with some key words like average and avoid
--created by jiavan.

// b.awk
{
    while (match($0, /[a-zA-Z]+?av[a-zA-Z]+?/)) {
        print(substr($0, RSTART, RLENGTH));
        $0 = substr($0, RSTART + RLENGTH);
    }
}

// result
$ awk -f b.awk words.txt
average
avoid
av
jiavan

因此在 TX 遊戲中個人 ID 是 Ji**an 這樣顯示的 :-)

本文僅提供給正在拉屎的人閱讀,不作參考。

原文出處 https://github.com/Jiavan/jia... 以爲對你有幫助就給個star吧
相關文章
相關標籤/搜索