一、介紹
awk
是一種編程語言(解釋性語言,不需要編譯),用於數據截取和報告的工具awk
自動搜索輸入的文件,並把每個輸入行切分成多個字段(字段:根據分隔符分割成的單元)- 擅長處理數據庫和表型數據。適合編寫短小一次性程序
centos
默認的awk
使用的是gawk
,系統將awk
通過軟鏈接來指向gawk
- 可以使用新的內置函數和變量
- 在缺省的情況下,它使用擴展的正則表達式
awk
不需要聲明變量的數據類型,它內置字符串類型和數值類型
二、命令格式
awk [OPTIONS] [--] program filename_list
選項 | 說明 |
---|---|
-f program -file | 指定包含了awk命令的文件,不是從命令行參數中去讀取 可以通過-f選項指定多個包含awk命令文件 |
-F ‘fs’ --field -separator | 指定分隔符即爲定義FS變量對應的值 |
-v var=val | 在程序開始之前,將val這個值賦給var這個變量 |
-d[file] | 將全局變量的類型和最終值排序,並將排序好後的結果打印輸出到文件中 |
-V | 顯示awk的版本 |
三、使用方法及範例
3.1 awk的核心
- PROGRAM——'pattern{action}'
3.2 關於pattern { action }的說明:
pattern
與action
並非同時存在,可以省略其中一個- 如果
action
被省略,默認動作是將每個匹配的行輸出 - 如果
pattern
被省略,對於每行都會執行動作
awk基本操作流程:
- 從輸入流中讀取一行內容,然後使用
pattern{action}
去處理 - 對讀取的行進行掃描搜索,搜索行中是否有內容被pattern匹配
- 如果行被
pattern
匹配成功,則執行動作{action}
;如果行中內容不被pattern
匹配,則不執行 - 繼續從輸入流中讀取新的一行,重複上述幾個步驟
例一:簡單理解awk
問題描述:
file1
文件第一列爲員工名字,第二列爲時薪,第三列爲工作時長- 打印輸出員工的名字、時薪和工作時長
執行命令:
[root@CentOS7 commands]# cat file1
Sam 50 8
Jiangle 55 9
Tom 40 6
Tim 60 9
[root@CentOS7 commands]# awk '{print $1,$2,$3}' file1
Sam 50 8
Jiangle 55 9
Tom 40 6
Tim 60 9
說明:
awk
命令後面的程序用單引號引起來,單引號後面的部分爲輸入文件- 單引號中包圍的內容是一個
awk
程序(program),即模式-動作語句(pattern-action)
3.3 pattern詳細說明
pattern
,即模式,是決定awk
程序中定義的動作action是否能夠被執行的關鍵pattern
支持的規則:正則表達式,字符串與數字比較,流程控制語句
例二:pattern——控制輸出條件1
問題描述:
file1
文件第一列爲員工名字,第二列爲時薪,第三列爲工作時長- 打印輸出時薪大於等於50的員工名字和總薪資
執行命令:
[root@CentOS7 commands]# cat file1
Sam 50 8
Jiangle 55 9
Tom 40 6
Tim 60 9
[root@CentOS7 commands]# awk '$2>=50 {print $1,$2*$3}' file1
Sam 400
Jiangle 495
Tim 540
說明:
- 其中模式
pattern
爲'$2>=50'
,表示掃描每一個輸入的行,如果第二列大於0,則執行動作action
,否則不執行action
- 動作
action
爲'{ print $1,$2*$3 }'
,模式匹配成功後執行的對應動作,該動作用於打印輸出第一個字段和第二、三字段的乘積
模式表示方式彙總:
模式 | 說明 |
---|---|
/regexp/ |
正則之字符串匹配模式/regexp/(拓展的正則表達式) 例如:expression ~ /regexpr/表示當前輸入行包含能被regexpr匹配的子字符串時,該模式被匹配 |
relational expression |
當表達式擁有一個數值形式的值,運算符要求一個字符串值,則awk會將該數值自動轉換成字符串 當表達式擁有一個字符串形式的值,運算符要求一個數值,則awk會將該字符串值自動轉換成數值 關於表達式真與假的說明:如果一個表達式,對當前述入行的求值結果非零或不爲空,那麼該行就被匹配 如果比較字符串,比較時是逐字符依賴ASCII字符表比較 |
pattern 1 && pattern2 |
只有當pattern1和pattern2都匹配了,纔會執行action |
pattern1 || pattern2 |
當pattern1和pattern2其中一個匹配了,就會執行action |
比較運算符彙總
運算符 | 說明 |
---|---|
< | 小於 |
<= | 小於等於 |
== | 等於 |
!= | 不等於 |
> | 大於 |
>= | 大於等於 |
~ | 匹配 |
!~ | 不匹配 |
表達式運算符彙總(也可以用在action)
操作 | 運算符 | 舉例 |
---|---|---|
賦值 | =、+=、-=、*=、/=、^= | sum+=i ,即sum=sum+i |
條件表達式 | ?: | x?y:z ,若x爲真則爲y,否則爲z |
邏輯或 | || | x\|\|y ,x或y爲真,則表達式爲真 |
邏輯與 | && | x&&y ,x與y爲真,則表達式爲真 |
數組成員 | in | i in a ,i在a中 |
字段 | $ | $1 表示輸入行的第一個字段 |
組合 | ( ) | $(2+1) 表示第三個字段 |
匹配 不匹配 |
~ !~ |
|
自增 自減 |
++ – |
例三:pattern——控制輸出條件2
問題描述:
- 打印輸出
file2
第一和二個字段都爲數字或第三和四個字段都爲字母的行
執行命令:
[root@CentOS7 commands]# cat file2
1 2 3 4
1 2 a b
a 1 4 3
1 a 2 b
[root@CentOS7 commands]# awk '($1~/[0-9]/ && $2~/[0-9]/)||($3~/[a-zA-Z]/ && $4~/[a-zA-Z]/)' file2
1 2 3 4
1 2 a b
說明:
$1~/[0-9]/
表示匹配第一列中包含數字0-9,其中的pattern
爲[0-9]$3~/[a-zA-Z]/
表示匹配任意大小寫字母
3.4 action詳細說明
關鍵字和變量
- 關鍵字
關鍵字 | 說明 |
---|---|
BEGIN |
放在程序開頭,當awk 從輸入流中讀取數據之前,BEGIN 語句開始執行(初始化),可以執行多個BEGIN |
END |
放在程序末尾,當所有輸入流被讀取完畢,END 語句開始執行(掃尾),可以執行多個END |
- 內建變量
變量 | 說明 |
---|---|
$n |
當前記錄的第n個字段,字段間由FS分隔 |
$0 |
完整的輸入記錄 |
FS |
Field Separator,表示字符分隔符,即讀取輸入流時,以FS作爲字段分隔的依據,默認爲空格符 |
RS |
Record Separator,表示記錄分隔符,即讀取輸入流時,以RS作爲記錄分隔的依據,默認是一個換行符 |
OFS |
Output Field Separator,表示輸出字段分隔符,默認爲空格符 |
ORS |
Output Record Separator,表示輸出記錄分隔符,默認爲換行符 |
NF |
Number of Field,表示每一行的字段數目 |
NR |
Number of Row,記錄讀取的行的行號 |
IGNORECASE |
IGNORECASE如果爲真,則進行忽略大小寫的匹配 |
例四:action——控制語句輸出1
問題描述:
file1
文件第一列爲員工名字,第二列爲時薪,第三列爲工作時長- 打印輸出每一個員工名字和總薪資,添加一個表頭說明,中間用":"隔開
執行命令:
[root@CentOS7 commands]# cat file1
Sam 50 8
Jiangle 55 9
Tom 40 6
Tim 60 9
[root@CentOS7 commands]# awk 'BEGIN{OFS=":";ORS="\n\n"} BEGIN{print "name:total_salary"} {print $1,$2*$3}' file1
name:total_salary
Sam:400
Jiangle:495
Tom:240
Tim:540
說明:
- 第一個
BEGIN
語句是控制輸出字段分隔符OFS
和輸出記錄分隔符ORS
- 第二個
BEGIN
語句是輸出字符串"name:total_salary"
- 執行完兩個BEGIN後,
awk
再從輸入流中讀取處理數據 - 注意:對變量
FS
、OFS
和ORS
賦值時,需要使用雙引號,不能沒有引號或使用單引號
格式化輸出語句
action
的格式化輸出語句通過printf
實現,在print
語句中,多個變量之間使用逗號作爲分隔符,對變量進行分隔
- printf語法格式:
printf(format,expression1,expression2…)
- 參數
format
包含“%”、對齊方式、格式控制字符、字符串最大寬度
printf格式控制字符
格式字符 | 說明 |
---|---|
- |
左對齊修飾符,默認爲右對齊 |
# |
顯示8 進制整數時在前面加個0 顯示16 進制整數時在前面加0x |
+ |
顯示使用d 、e 、f 和g 轉換的整數時,加上正負號± |
0 |
用0而不是空白符來填充所顯示的值,即用字符’0’填充 |
%c |
表示一個ASCII字符 |
%s |
表示一個字符串 |
%d |
表示一個十進制整數 |
%u |
表示一個無符號的十進制數 |
%x |
表示一個十六進制數 |
%o |
表示一個八進制數 |
%f |
表示一個浮點數 |
%e |
用科學計數法(e 記數法),表示一個浮點數 |
%g |
選擇e或f中較短的一種形式 |
上面差不多就是printf
的常用格式輸出了,下面是一些常用的複合。就是啊,附和!!!
複合格式字符 | 說明 |
---|---|
%10d |
十進制數佔10列 |
%010d |
十進制數佔10列,前面用字符’0’填充 |
%+10d |
十進制數佔10列,包含數值的符號(±) |
%#10x |
十六進制數佔10列,顯示前綴0x |
%-10.3f |
浮點數左對齊佔10列,保留3位小數 |
%0+10.3f |
浮點數右對齊佔10列,保留3位小數,顯示符號,左補齊填充字符’0’ |
%10s |
字符串右對齊,佔10列 |
%-10s |
字符串左對齊,佔10列 |
例五:action——控制語句輸出2
問題描述:
file1
文件第一列爲員工名字,第二列爲時薪,第三列爲工作時長- 打印輸出每一個員工編號(所在行數即爲編號)、名字和總薪資;員工編號左對齊佔5列,名字右對齊佔10列,總薪資佔10列右對齊保留兩位小數
執行命令:
[root@CentOS7 commands]# cat file1
Sam 50 8
Jiangle 55 9
Tom 40 6
Tim 60 9
[root@CentOS7 commands]# awk 'BEGIN{printf "%-5s%10s%10s\n","ID","NAME","SALARY"}{printf("%-5d%10s%10.2f\n",NR,$1,$(NF-1)*$NF))}' file1
ID NAME SALARY
1 Sam 400.00
2 Jiangle 495.00
3 Tom 240.00
4 Tim 540.00
說明:
NF
表示當前行的字段數(列數),$NF
表示當前行的最後一個字段值- 這裏的
$(NF-1)*$NF
與$2*$3
相同 printf
不會自動換行,需要添加換行符"\n"
才能換行
四、awk進階
4.1 輸出重定向
4.1.2 輸出重定向到文件
- 使用
>>
重定向,不清空文件內容,將內容追加到文件尾部 - 使用
>
重定向,清空文件內容,再把內容寫入文件
例六:輸出重定向到文件
問題描述:
file1
文件第一列爲員工名字,第二列爲時薪,第三列爲工作時長- 將時薪大於等於50的員工的信息保存到
new_file1
中
執行命令:
[root@CentOS7 commands]# cat file1
Sam 50 8
Jiangle 55 9
Tom 40 6
Tim 60 9
[root@CentOS7 commands]# awk '$2>=50 {print $0 > "new_file1"}' file1
[root@CentOS7 commands]# cat new_file1
Sam 50 8
Jiangle 55 9
Tim 60 9
說明:
- 重定向時,文件名必須要用雙引號引起來,否則會被當作一個未初始化的變量
>
重定向時,會覆蓋目標文件的內容
4.1.2 輸出重定向到管道
- 使用管道命令
|
進行數據的處理
例七:輸出重定向到管道
問題描述:
file1
文件第一列爲員工名字,第二列爲時薪,第三列爲工作時長- 按照總薪資降序進行排序,名字佔10列左對齊,時薪佔10列左對齊,工作時長佔10列左對齊,總薪資佔10列左對齊
執行命令:
[root@CentOS7 commands]# cat file1
Sam 50 8
Jiangle 55 9
Tom 40 6
Tim 60 9
[root@CentOS7 commands]# awk '{printf("%-10s%-10d%-10d%-10d\n",$1,$2,$3,$2*$3) | "sort -nrk 4 "}' file1
Tim 60 9 540
Jiangle 55 9 495
Sam 50 8 400
Tom 40 6 240
說明:
- 語句
{printf(...) | "sort..."}
中的sort
必須用雙引號引起來 sort
中-n
表示按照字符串的數值順序比較;-r
表示逆序比較,默認爲升序;-k 4
表示以第4個字段(第4列)爲關鍵字進行比較- 也可以將
awk
的格式化輸出通過管道傳遞給sort
命令,也能實現排序並格式化輸出,等價命令爲:awk '{printf("%-10s%-10d%-10d%-10d\n",$1,$2,$3,$2*$3)}' file1 | sort -nrk 4
4.2 流程控制
流程控制語句中,if-else
用於決策,while
、for
、do whlie
用於循環,break
、continue
用於控制循環
4.2.1 if-else語句
語法結構
{
if (expression)
statements
else
statements
}
或者
{if (expression) statements;else statements}
例八:簡單使用if-else語句
[root@CentOS7 commands]# cat file1
Sam 50 8
Jiangle 55 9
Tom 40 6
Tim 60 9
[root@CentOS7 commands]# cat if.awk
#!/bin/bash
{
if($2>=50)
printf("%s has a good salary!\n",$1)
else
printf("%s need to change a job!\n",$1)
}
[root@CentOS7 commands]# awk -f if.awk file1
Sam has a good salary!
Jiangle has a good salary!
Tom need to change a job!
Tim has a good salary!
說明:
awk -f
可以指定文件作爲pattern{action}
,上述例子並未指定pattern
- 從上述例子可以看出,時薪小於50的,就可以換工作了(hahaa,偶爾皮一下🐶)
4.2.2 while語句
語法結構
{
while (expression)
{
statement1
statement2
...
}
}
或者
{while (expression){statement1;statement2;...}}
例九:簡單的使用while語句
問題描述:
- 將
data
文件中的數按行求和並輸出
執行命令:
[root@CentOS7 commands]# cat data
1 2 3 4
5 6 7 8 9
6 6 6 6 6 6
10 20 30 40 50
[root@CentOS7 commands]# cat while.awk
#!/bin/bash
{
i=1
sum=0
while(i<=NF)
{
sum+=$i
i++
}
printf("Line %d, sum is %d\n",NR,sum)
}
[root@CentOS7 commands]# awk -f while.awk data
Line 1, sum is 10
Line 2, sum is 35
Line 3, sum is 36
Line 4, sum is 150
說明:
- 每從輸入流讀取一行,
while
循環就會被執行 - 當
expression
的值爲真時,進入while
循環
4.2.3 for語句
語法結構
{
for(expresion1;expression2;expression3)
{
statement1
statement2
}
}
或者
{ for(expresion1;expression2;expression3){statement1;statement2;...}}
expression1
:進入for
循環之前執行一次該語句。一般用於對變量的初始化expression2
:每執行一次循環後,都會執行一次該語句,如果結果爲真,則繼續循環,反之退出循環。一般用於循環的條件判斷expression3
:每執行一次循環後,都會執行一次該語句。一般用於做變量變化
例十:簡單的使用for語句
問題描述:
- 將
data
文件中的數按行求和並輸出
執行命令:
[root@CentOS7 commands]# cat data
1 2 3 4
5 6 7 8 9
6 6 6 6 6 6
10 20 30 40 50
[root@CentOS7 commands]# cat while.awk
#!/bin/bash
{
sum=0
for(i=1;i<=NF;i++)
sum+=$i
printf("Line %d, sum is %d\n",NR,sum)
}
[root@CentOS7 commands]# awk -f for.awk data
Line 1, sum is 10
Line 2, sum is 35
Line 3, sum is 36
Line 4, sum is 150
循環語句裏面也可以使用break
、continue
語句,具體的使用這裏就不再贅述了。
我的🐴🦆,8k+字!!!第一次總結這麼多,累遼~~