Linux三大劍客之awk

暖夏未眠丶發表於2018-03-01

摘要:
一、概述 awk的名稱來源於其最初設計者Alfred V. Aho, Peter J. Weinberger, and Brian W. Kernighan的姓氏。awk最原始的版本是1977年在AT&T貝爾實驗室誕生的,awk經過改進生成的新的版本nawk,gawk,現在預設linux系統下日常使用的是gawk。

一、概述

awk的名稱來源於其最初設計者Alfred V. Aho, Peter J. Weinberger, and Brian W. Kernighan的姓氏。awk最原始的版本是1977年在AT&T貝爾實驗室誕生的,awk經過改進生成的新的版本nawk,gawk,現在預設linux系統下日常使用的是gawk。我目前使用的作業系統為CentOS Linux release 7.2.1511,系統自帶的awk版本為:GNU Awk 4.0.2。

二、awk的用途

  • 文字處理。
  • 格式化輸出文字、報告。
  • 數字運算(在我之前的文章中,探討過整數的算術運算,浮點運算可以使用awk)。
  • 執行字串操作。

三、系統內幾個有關awk命令的區別與聯絡

通過命令,我們可以看到:

[awk@GeekDevOps ~]$ ls -l /bin/*awk
lrwxrwxrwx. 1 root root      4 11月 20 10:41 /bin/awk -> gawk
-rwxr-xr-x. 1 root root 514136 6月  10 2014 /bin/dgawk
-rwxr-xr-x. 1 root root 428576 6月  10 2014 /bin/gawk
-rwxr-xr-x. 1 root root   3188 6月  10 2014 /bin/igawk
-rwxr-xr-x. 1 root root 428600 6月  10 2014 /bin/pgawk複製程式碼

與awk有關的命令竟然有這麼多!在用whatis命令看一下這些都是些什麼鬼:

[awk@GeekDevOps ~]$ whatis awk gawk dgawk pgawk igawk
awk (1)              - pattern scanning and processing language
gawk (1)             - pattern scanning and processing language
dgawk (1)            - pattern scanning and processing language
pgawk (1)            - pattern scanning and processing language
igawk (1)            - gawk with include files複製程式碼

不太確信以上結果,我又使用man、info挨個看了一下,結果awk、gawk、dgawk、pgawk都是gawk,線上手冊一模一樣。唯獨igawk與前面四個不太一樣,是包含檔案的gawk,其實也是gawk。awk是gawk的一個軟連線,大家都是gawk!

四、awk的使用

4.1 理解awk的工作原理

image

Read

awk從輸入流(檔案,管道或者標準輸入)中讀取一行,然後儲存到記憶體中。

Execute

所有的AWK命令都依次在輸入文字上執行。預設情況下,awk會對每一行執行命令,可以通過提供模式限制這種行為。

Repeat

處理過程不斷重複,從首行開始直到到達檔案結尾。

建立marks.txt檔案備用:

[awk@GeekDevOps ~]$ echo "1)  Amit    Physics  80
> 2)  Rahul   Maths    90
> 3)  Shyam   Biology  87
> 4)  Kedar   English  85
> 5)  Hari    History  89">marks.txt複製程式碼
4.2 awk的結構

BEGIN 語句塊

BEGIN語句塊的語法:

BEGIN {awk-commands}複製程式碼

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

BODY 語句塊

BODY語句塊的語法:

/pattern/ {awk-commands}複製程式碼

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

END 語句塊

END語句塊的語法:

END {awk-commands}複製程式碼

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

結合以上2點,舉個例子來理解一下:

[awk@GeekDevOps ~]$ awk BEGIN'{printf "Sr NO\tName\tSub\tMarks\n"} {print} END{print "Done!"}' marks.txt
Sr NO   Name    Sub     Marks
1)  Amit    Physics  80
2)  Rahul   Maths    90
3)  Shyam   Biology  87
4)  Kedar   English  85
5)  Hari    History  89
Done!
[awk@GeekDevOps ~]$ awk BEGIN'{printf "Sr NO\tName\tSub\tMarks\n"} END{print "Done!"}' marks.txt
Sr NO   Name    Sub     Marks
Done!複製程式碼

在本例中,BEGIN塊被執行一次,給文字內容增加了一行標題。body塊從文字第一行掃描直至檔案末尾。END塊也僅僅執行了一次。

4.3 使用awk

通常情況下,awk命令較簡短時我們直接按照以下方式執行awk命令:

awk 'program' input-file1 input-file2 …複製程式碼

如果awk內容較多的話,我們以以下格式來執行awk命令(此處program-file為awk指令碼內容):

awk -f program-file input-file1 input-file2 …複製程式碼

awk是一門解釋型的語言,所以也可以像執行bash shell一樣執行awk指令碼:

#!/bin/awk -f
BEGIN{print "My name is Ivan Du!"}複製程式碼
[awk@GeekDevOps ~]$ chmod u+x GeekDevOps.awk
[awk@GeekDevOps ~]$ ./GeekDevOps.awk
My name is Ivan Du!複製程式碼
4.4 列印某列或某欄位
[awk@GeekDevOps ~]$ cat best.txt
www     CC      ICBC
[awk@GeekDevOps ~]$ awk '{print $1}' best.txt
www
[awk@GeekDevOps ~]$ awk '{print $3}' best.txt
ICBC
[awk@GeekDevOps ~]$ awk -F "\t" '{print $3}' best.txt
ICBC複製程式碼

預設情況下,awk以空格、製表符等符號為分隔符。從每一行的第一個字串開始掃描,第一個字串為

Linux三大劍客之awkLinux三大劍客之awkLinux三大劍客之awk個字串為
1
,
N
n,如果首行是空格之類的字元那也算。

4.5 列印匹配模式的列

當模式匹配成功時,預設情況下awk會列印該行,但是也可以讓它只列印指定的欄位。例如,下面的例子中,只會列印出匹配模式的第三和第四個欄位。

[awk@GeekDevOps ~]$ awk '/a/ {print $3 " " $4}' marks.txt
Maths 90
Biology 87
English 85
History 89複製程式碼

匹配指定檔案中帶u的行,並列印第四列與第三列,中間以一個橫向製表符隔開。

[awk@GeekDevOps ~]$ awk '/u/ {print $4"\t"$3}' marks.txt
90      Maths複製程式碼
4.6 統計文字總行數
[awk@GeekDevOps ~]$ awk 'BEGIN{ct=0} {++ct} END{print "Count:",ct}' marks.txt
Count: 5複製程式碼

此行命令中,BEGIN部分其實是可以省略的。

4.7 列印匹配模式的總行數
[awk@GeekDevOps ~]$ awk '/a/ {++ct} END{print "Count:",ct}' marks.txt
Count: 4複製程式碼

此處的BEGIN部分不能出現,否則報錯。

4.8 列印超過指定長度的行
[awk@GeekDevOps ~]$ awk 'length($0) > 22' marks.txt
1)  Amit    Physics  80
2)  Rahul   Maths    90
3)  Shyam   Biology  87
4)  Kedar   English  85
5)  Hari    History  89複製程式碼

mark.txt檔案是通過空格來控制對齊的,每一行加上空格一共是22個字元。

4.9 ARGC命令列引數個數
[awk@GeekDevOps ~]$ awk 'BEGIN{print "Arguments=" ARGC}' One Two Three Four
Arguments=5複製程式碼
4.10 ARGV命令列引數陣列
[awk@GeekDevOps ~]$ awk 'BEGIN{for (i=0 ;i<ARGC-1;++i ){printf "ARGC[%d]=%s\n",i,ARGV[i]}}' One Two Three Four
ARGC[0]=awk
ARGC[1]=One
ARGC[2]=Two
ARGC[3]=Three複製程式碼
4.11 ENVIRON環境變數
[awk@GeekDevOps ~]$ awk 'BEGIN{print ENVIRON["PATH"]}'
/usr/local/bin:/usr/bin:/usr/local/sbin:/usr/sbin:/home/awk/.local/bin:/home/awk/bin複製程式碼
4.12 FILENAME當前檔名
[awk@GeekDevOps ~]$ awk 'END{print FILENAME}' marks.txt 
marks.txt複製程式碼

注意:此處使用的是END,如果省略則會列印出5個檔名稱,這個檔案一5行。

4.13 常用的awk內建變數
變數名屬性
$0當前記錄
Linux三大劍客之awkLinux三大劍客之awk
1
n
當前記錄的第N個欄位
FS讀入欄位的分隔符,預設為空格
RS讀入記錄分隔符,預設為換行符
NF列,當前記錄中的欄位個數
NR行,已經讀出的行數,也就是行號
OFS輸出欄位分隔符,預設為空格
ORS輸出記錄分隔符,預設為換行符
[awk@GeekDevOps ~]$ awk -F " " '{print $4}' marks.txt 
80
90
87
85
89
[awk@GeekDevOps ~]$ awk '{print $3}' marks.txt 
Physics
Maths
Biology
English
History
[awk@GeekDevOps ~]$ awk 'BEGIN{FS=" "}{print $3}' marks.txt 
Physics
Maths
Biology
English
History複製程式碼

以上三種寫法都是一樣的效果。

[awk@GeekDevOps ~]$ ls -al | awk 'BEGIN{size=0}{size+=$5}END{print size/1024/1024 "MB"}'
128.017MB
[awk@GeekDevOps ~]$ ls -al|awk 'NR>1{size+=$5} END{print size/1024/1024 "MB"}'
128.017MB複製程式碼
[awk@GeekDevOps ~]$ ls -al|awk 'NR==1{print $2/1024 "MB"}'
128.035MB複製程式碼

以上兩個程式碼片中,都是統計當前目錄下所有的檔案(包括隱藏檔案)所佔磁碟空間的大小,非常有用。

[awk@GeekDevOps ~]$ awk 'BEGIN{print "OFS=" OFS}' marks.txt
OFS=複製程式碼
4.14 awk中的算術運算

在awk中,支援像C語言中一樣的算術運算。在前面的文章中介紹過,Linux系統中無法對非整型數字直接進行算術運算,要對浮點型的資料就行算術運算我們可以使用awk來實現。

[awk@GeekDevOps ~]$ awk 'BEGIN{A=2.8;B=7;print A/B}'
0.4複製程式碼

在這一部分中,awk中的增減運算子、賦值運算子、關係操作符、邏輯運算子、三元操作符等均與C語言類似,不贅述。

4.15 awk中的一元操作符
[awk@GeekDevOps ~]$ awk 'BEGIN{A=2.8;A=+A;print A}'
2.8複製程式碼
4.16 awk中的指數操作符
[awk@GeekDevOps ~]$ awk 'BEGIN{A=2.8;A=A^3;print A}'
21.952
[awk@GeekDevOps ~]$ awk 'BEGIN{A=2.8;A=A**3;print A}'
21.952複製程式碼
4.17 awk中的字串連線操作符
[awk@GeekDevOps ~]$ awk 'BEGIN{str1="Hello";str2=",GeekDevOps";str3=str1 str2;print str3}'
Hello,GeekDevOps複製程式碼
4.18 awk中的陣列

陣列的定義與C語言有類似的地方,也有差別,使用的時候需要注意一下,有的資料上說awk中不支援多維陣列,通過awk的GUN的文件,我們可以看到,awk也是支援多維陣列的。刪除陣列元素使用delete語句:

[awk@GeekDevOps ~]$ awk 'BEGIN{array[0][0]=2;array[0][1]=3;array[1][0]=4;array[1][1]=8;for(i=0;i<2;i++){for(j=0;j<2;j++){printf "array[%d][%d]=%d\n",i,j, array[i][j]}}delete array[0][0];print array[0][0] "\t" array[0][1]}'
array[0][0]=2
array[0][1]=3
array[1][0]=4
array[1][1]=8
        3複製程式碼
4.19 awk中的控制結構

在awk中,也支援類似C語言一樣的程式結構,支援if-else、while、do-while、for、switch、break、continue、nex、nextfile、exit。相信很多小夥伴都學習過C語言,與C語言一樣的就不在贅述。

[awk@GeekDevOps ~]$ awk 'NF != 4 {
    printf("%s:%d: skipped: NF != 4\n", FILENAME, FNR) > "/dev/stderr"
    next
}'

-:1: skipped: NF != 4

-:2: skipped: NF != 4
...複製程式碼
[awk@GeekDevOps ~]$ awk 'BEGIN {
    if (("date" | getline date_now) <= 0) {
        print "Can not get system date" > "/dev/stderr"
        exit 1
    }
    print "Current date is", date_now
    close("date")
}'
Current date is 2018年 02月 28日 星期三 23:05:16 CST複製程式碼
4.20 awk中的函式

在awk中,支援內建函式與使用者自定義函式。

常用數學計算函式

atan2(y, x)

Return the arctangent of y / x in radians. You can use ‘pi = atan2(0, -1)’ to retrieve the value of pi.複製程式碼

cos(x)

Return the cosine of x, with x in radians.複製程式碼

exp(x)

Return the exponential of x (e ^ x) or report an error if x is out of range. The range of values x can have depends on your machine’s floating-point representation.複製程式碼

int(x)

Return the nearest integer to x, located between x and zero and truncated toward zero. For example, int(3) is 3, int(3.9) is 3, int(-3.9) is -3, and int(-3) is -3 as well.複製程式碼

log(x)

Return the natural logarithm of x, if x is positive; otherwise, return NaN (“not a number”) on IEEE 754 systems. Additionally, gawk prints a warning message when x is negative.複製程式碼

rand()

Return a random number. The values of rand() are uniformly distributed between zero and one. The value could be zero but is never one.複製程式碼

sin(x)

Return the sine of x, with x in radians.複製程式碼

sqrt(x)

Return the positive square root of x. gawk prints a warning message if x is negative. Thus, sqrt(4) is 2.複製程式碼

srand([x])

Set the starting point, or seed, for generating random numbers to the value x. 
複製程式碼

字串函式

asort(arr [, d [, how] ])
asorti(arr [, d [, how] ])
gsub(regex, sub, string)
index(str, sub)
length(str)
match(str, regex)
split(str, arr, regex)
sprintf(format, expr-list)
strtonum(str)
sub(regex, sub, string)
substr(str, start, l)
tolower(str)
toupper(str)
複製程式碼

時間函式

systime
mktime(datespec)
strftime([format [, timestamp[, utc-flag]]])
複製程式碼

位元組操作函式

and
compl
lshift
rshift
or
xor複製程式碼

自定義函式類似於C語言,參閱GUN網站function部分。

4.21 awk中的正規表示式
[awk@GeekDevOps ~]$ echo -e "My name is IVAN DU.\nMy blog is GeekDevOps.\nWelcome to my blog."|awk '/My+/'
My name is IVAN DU.
My blog is GeekDevOps.
[awk@GeekDevOps ~]$ echo -e "My name is IVAN DU.\nMy blog is GeekDevOps.\nWelcome to my blog."|awk '/^W/'
Welcome to my blog.複製程式碼

五、參考資料

www.tutorialspoint.com/awk/index.h…
www.gnu.org/software/ga…

版權宣告:本文內容由網際網路使用者自發貢獻,版權歸作者所有,本社群不擁有所有權,也不承擔相關法律責任。如果您發現本社群中有涉嫌抄襲的內容,歡迎傳送郵件至:yqgroup@service.aliyun.com 進行舉報,並提供相關證據,一經查實,本社群將立刻刪除涉嫌侵權內容。
Linux三大劍客之awk

用雲棲社群APP,舒服~

原文連結


相關文章