awk命令——《Linux日常》

一、介紹

  • 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 }的說明:

  • patternaction並非同時存在,可以省略其中一個
  • 如果action被省略,默認動作是將每個匹配的行輸出
  • 如果pattern被省略,對於每行都會執行動作

awk基本操作流程:

  1. 從輸入流中讀取一行內容,然後使用pattern{action}去處理
  2. 對讀取的行進行掃描搜索,搜索行中是否有內容被pattern匹配
  3. 如果行被pattern匹配成功,則執行動作{action};如果行中內容不被pattern匹配,則不執行
  4. 繼續從輸入流中讀取新的一行,重複上述幾個步驟

例一:簡單理解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再從輸入流中讀取處理數據
  • 注意:對變量FSOFSORS賦值時,需要使用雙引號,不能沒有引號或使用單引號

格式化輸出語句

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用於決策,whilefordo whlie用於循環,breakcontinue用於控制循環

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

循環語句裏面也可以使用breakcontinue語句,具體的使用這裏就不再贅述了。

我的🐴🦆,8k+字!!!第一次總結這麼多,累遼~~

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