Linux 文本處理三劍客之 Awk

AWK是一種優良的文本處理工具。它不僅是 Linux 中也是任何環境中現有的功能最強大的數據處理引擎之一。這種編程及數據操作語言(其名稱得自於它的創始人 Alfred Aho 、Peter Weinberger 和 Brian Kernighan 姓氏的首個字母)的最大功能取決於一個人所擁有的知識。AWK 提供了極其強大的功能:可以進行樣式裝入、流控制、數學運算符、進程控制語句甚至於內置的變量和函數。它具備了一個完整的語言所應具有的幾乎所有精美特性。實際上 AWK 的確擁有自己的語言:AWK 程序設計語言, 三位創建者已將它正式定義爲“樣式掃描和處理語言”。它允許您創建簡短的程序,這些程序讀取輸入文件、爲數據排序、處理數據、對輸入執行計算以及生成報表,還有無數其他的功能。

最簡單地說, AWK 是一種用於處理文本的編程語言工具。AWK 在很多方面類似於 shell 編程語言,儘管 AWK 具有完全屬於其本身的語法。它的設計思想來源於 SNOBOL4 、sed 、Marc Rochkind設計的有效性語言、語言工具 yacc 和 lex ,當然還從 C 語言中獲取了一些優秀的思想。在最初創造 AWK 時,其目的是用於文本處理,並且這種語言的基礎是,只要在輸入數據中有模式匹配,就執行一系列指令。該實用工具掃描文件中的每一行,查找與命令行中所給定內容相匹配的模式。如果發現匹配內容,則進行下一個編程步驟。如果找不到匹配內容,則繼續處理下一行。

  • Awk 的語法:

awk '{pattern + action}' 或者 awk 'pattern {action}'

awk [ -F re] [parameter...] ['prog'] [-f progfile]

  • 參數說明:

-F re:允許awk更改其字段分隔符

parameter: 該參數幫助爲不同的變量賦值。

'prog': awk的程序語句段。這個語句段必須用單括號:'和'括起,以防被shell解釋。這個程序語句段的標準形式爲:'pattern {action}'

其中 pattern 參數可以是 egrep 正則表達式中的任何一個,它可以使用語法 /re/ 再加上一些樣式匹配技巧構成。與 sed 類似,你也可以使用"," 分開兩樣式以選擇某個範圍。action參數總是被大括號包圍,它由一系列awk語句組成,各語句之間用";"分隔。awk解釋它們,並在pattern給定的樣式匹配的記錄上執行其操作。與shell類似,你也可以使用“#”作爲註釋符,它使“#”到行尾的內容成爲註釋,在解釋執行時,它們將被忽略。你可以省略pattern和 action之一,但不能兩者同時省略,當省略pattern時沒有樣式匹配,表示對所有行(記錄)均執行操作,省略action時執行缺省的操作——在標準輸出上顯示。

-f progfile:允許awk調用並執行progfile指定有程序文件。progfile是一個文本文件,他必須符合awk的語法。

in_file:awk的輸入文件,awk允許對多個輸入文件進行處理。值得注意的是awk不修改輸入文件。如果未指定輸入文件,awk將接受標準輸入,並將結果顯示在標準輸出上。awk支持輸入輸出重定向。

awk處理的工作與數據庫的處理方式有相同之處,其相同處之一就是awk支持對記錄和字段的處理,其中對字段的處理是grep和sed不能實現的,這也是awk優於二者的原因之一。在awk中,缺省的情況下總是將文本文件中的一行視爲一個記錄,而將一行中的某一部分作爲記錄中的一個字段。爲了操作這些不同的字段,awk借用shell的方法,用1,2,3...這樣的方式來順序地表示行(記錄)中的不同字段。特殊地,awk用0表示整個行(記錄)。不同的字段之間是用稱作分隔符字符分隔開的。系統默認的分隔符是空格。awk允許在命令行中用-F re的形式來改變這個分隔符。事實上,awk用一個內置的變量RS來記憶這個分隔符。awk中有好幾個這樣的內置變量,例如,記錄分隔符變量RS、當前工作的記錄數NR等等,這些內置的變量可以在awk程序中引用或修改,例如,你可以利用NR變量在模式匹配中指定工作範圍,也可以通過修改記錄分隔符RS讓一個特殊字符而不是換行符作爲記錄的分隔符。

  • Awk的內置變量

ARGC命令行參數個數(不包括awk的選項和awk的程序內容)

ARGIND 當前正在處理的ARGV中的文件的索引值(同時處理多個文件時會用到)

ARGV 命令行參數序列數組,下標從0開始

CONVFMT 數字轉換格式,和C語言中的數字輸出格式化類似,默認爲"%.6g"

ENVIRON 當前系統的環境變量

ERRNO 出錯時的錯誤信息

FIELDWIDTHS 以空格分隔的字段寬度,awk會用指定的寬度替換變量FS指定的分隔符

FILENAME 當前正在處理的文件名,該變量不能在BEGIN塊中使用

FNR當前處理的記錄號

FS 字段的分隔符,默認爲空格

IGNORECASE 如果該變量設置爲非0值,在進行字符串匹配時忽略大小寫

NF 當前記錄中的字段個數

NR 已經讀出的記錄數

OFMT 數字的輸出格式

OFS 輸出的字段分隔符,默認爲空格

ORS 輸出的記錄分隔符,默認爲新行

RS 輸入記錄的分隔符,默認爲新行

RSTART 被match()函數匹配的字符串的起始位置,如果沒有匹配則爲0(從1開始)

RLENGTH 被match()函數匹配的字符串的長度

SUBSEP數組中多個下標的分隔符,默認爲"\034"

  • 內置函數

    Awk 之所以成爲一種優秀的程序設計語言的原因之一是它吸收了某些優秀的程序設計語言(例如C)語言的許多優點。這些優點之一就是內置函數的使用,awk定義並支持了一系列的內置函數,由於這些函數的使用,使得awk提供的功能更爲完善和強大,例如,awk使用了一系列的字符串處理內置函數(這些函數看起來與C 語言的字符串處理函數相似,其使用方式與C語言中的函數也相差無幾),正是由於這些內置函數的使用,使awk處理字符串的功能更加強大。本文後面的附錄中列有一般的awk所提供的內置函數,這些內置函數也許與你的awk版本有些出入,因此,在使用之前,最好參考一下你的系統中的聯機幫助。

    Awk內置的字符串函數

    gsub(r,s)

    在整個$0中用s代替r

    gsub(r,s,t)

    在整個t中用s替代r

    index(s,t)

    返回s中字符串t的第一位置

    length(s)

    返回s長度

    match(s,r)

    測試s是否包含匹配r的字符串

    split(s,a,fs)

    在fs上將s分成序列a

    sprint(fmt,exp)

    返回經fmt格式化後的exp

    sub(r,s)

    用$0中最左邊最長的子串代替s

    substr(s,p)

    返回字符串s中從p開始的後綴部分

    substr(s,p,n)

    返回字符串s中從p開始長度爲n的後綴部分

    gsub函數有點類似於sed查找和替換。它允許替換一個字符串或字符爲另一個字符串或字符,並以正則表達式的形式執行。第一個函數作用於記錄$0,第二個gsub函數允許指定目標,然而,如果未指定目標,缺省爲$0。

    index(s,t)函數返回目標字符串s中查詢字符串t的首位置。length函數返回字符串s字符長度。

    match函數測試字符串s是否包含一個正則表達式r定義的匹配。

    split使用域分隔符fs將字符串s劃分爲指定序列a。

    sprint函數類似於printf函數,返回基本輸出格式fmt的結果字符串exp。

    sub(r,s)函數將用s替代$0中最左邊最長的子串,該子串被r匹配。

    substr(s,p)返回字符串s在位置p後的後綴。

    substr(s,p,n)同上,並指定子串長度爲n。

  • 顯示文本文件 /etc/passwd 匹配(含有)字符串"root"的所有行

  • awk '/root/' /etc/passwd

  • 由於顯示整個記錄(全行)是awk的缺省動作,因此可以省略action項

  • awk '/[Rr]oot/,/[Gg]f/ ' /etc/passwd

  • 顯示所有匹配 Root 或 root 的行與匹配 Gf 或 gf 的行之間的行,並顯示到標準輸出上

  • 顯示 /etc/passwd 有root 關鍵字的所有行,並顯示對應的名稱和 shell
  • awk -F: '/root/ {print $1,$7}' /etc/passwd
  • awk -F: '/^root/ {print $1,$7}' /etc/passwd  #錨定行首
  • 統計 /etc/passwd 文件名,每行的行號,每行的列數,對應的完整行內容
  • awk -F: '{printf ("filename:%10s, linenumber:%3s, column:%3s, content:%3s \n", FILENAME,NR,NF,$0)}' /etc/passwd
  • 顯示 /etc/passwd 的第二行信息
  • awk -F: 'NR==2{print "filename: "FILENAME, $0}' /etc/passwd

  • awk的過濾使用方法
  • ll -aF | awk '/^-/'
    ll -aF | awk '/^d/'

 

  • 指定特定的分隔符
  • pwd | awk -F "/" '{print $1,$2,$3}'

  • 指定特定的分隔符,查詢倒數第二列
  • pwd | awk -F/ '{print $0,$(NF-1)}'

  • 獲取第10到20行的第一列的信息
  • awk -F: '{if(NR<20 && NR>10) print $1}' /etc/passwd
  • awk '{if(NR>=10 && NR<=15) print $1}' /etc/passwd

  • 多分隔符的使用
  • awk -F "[-/]" 'NR == 1 {print NR,$0,"\n",$1,"\n",$2,"\n",$3}' /tmp/test.txt

  • BEGIN 和 END
  • cat /etc/passwd | awk -F: 'BEGIN{print "name, shell"} {print $1,$NF} END{print "hello  world"}'

  • 查看最近登錄最多的IP信息
  • last | awk '{S[$3]++} END{for(a in S ) {print S[a],a}}' |uniq| sort -rh
  • last | awk '{a[$3] += 1;} END {for (i in a) printf("%d %s\n", a[i], i);}' | sort -rh
  • awk每次讀取一行,$3就是IP,{S[$3]++} 是將IP作爲一個數組,統計IP所對應的數組元素自增1.END後面的語句是打印結果,只執行一次。sort -r 逆向排序 -h, --human-numeric-sort   使用易讀性數字

  •  結合正則過濾多個空格
  • ifconfig | grep "[eth*|lo]" | awk -F '[ ]+' '{print $1}'

  • awk編程--變量和賦值

  • 統計顯示/etc/passwd的賬戶
  • awk -F ':' 'BEGIN {count=0;} {name[count] = $1;count++;}; END{for (i = 0; i < NR; i++) print i, name[i]}' /etc/passwd
  • count是自定義變量。之前的action{}裏都是隻有一個print,其實print只是一個語句,而action{}可以有多個語句,以;號隔開

  • 取最大值和最小值
  • ll | awk 'BEGIN {max = 0} {if ($5>max) max=$5 } END {print "Max=", max}'
  • awk 'BEGIN {min = 65536} {if ($2+0 < min+0) min=$2 fi} END {print "Min=", min}'
  •  

  • 獲取本機 IP 地址
  • ifconfig eth0 | awk 'BEGIN{FS="[[:space:]:]+"} NR==2{print $4}'
  • 內建變量FS保存輸入域分隔符的值,默認是空格或tab,NR 已經讀出的記錄數,NR==2也就是取第2行

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章