1. 程式人生 > 其它 >linux三劍客之awk

linux三劍客之awk

1.awk

1.什麼是awk,主要作用是什麼?
awk主要擅長處理有規律的文字,主要用於做一些格式化處理,將文字按照指定的格式輸出。其中包含變數,迴圈以及陣列。

2.awk的格式:
格式1:
awk 選項 '規則' 檔案路徑
[root@localhost ~]# awk -F: '{print $1}' /etc/passwd
格式2:
標準輸出 | awk [選項] '匹配規則和處理規則'
[root@localhost ~]# cat /etc/passwd |awk -F: '{print $1}'

選項:-F 指定分隔符
規則:定位+命令
定位:
行號定位:NR==1
正則定位:awk -F: '//{print $1 $2}' 檔案路徑
沒有定位表示定位所有行
命令:{print $n}
匹配規則主要是正則表示式
處理規則就有很多了:
設定變數
設定陣列
陣列迴圈
加減乘數運算
字串拼接
匹配規則:1.字串
2.正則表示式
處理規則:BEGIN{} :BEGIN是在awk處理文字之前執行
// :使用的匹配規則
/正則/ # 該行內容匹配成功正則
$1 ~ /正則/ # 第一段內容匹配成功正則
$1 !~ /正則/ # 第一段內容沒有匹配成功正則
{} :迴圈(每次只處理一行資料)
END{} :當所有的處理全部執行完畢之後,執行END中的相關操作

案例1:列印第三行的第一列和第三列
awk -F: 'NR==3{print $1,$3}' /etc/passwd
案例2列印第三行到第五行的第一列和第三列
awk -F: 'NR>=3 && NR<=5 {print $1,$3}' /etc/passwd
案例3:列印前三行或者大於第8行的第一列和第三列
awk -F: 'NR<=3 || NR>=8 {print $1,$3}' /etc/passwd
案例4:列印所有的nologin結尾的第一列
awk -F: '/nologin$/ {print $1}' /etc/passwd
案例5:列印/etc/passwd的最後一列
awk -F: '{print $NF}' /etc/passwd
案例6:把/etc/passwd中的包含root的行打印出來
[root@localhost ~]# awk -F: '/root/' /etc/passwd
root:x:0:0:root:/root:/bin/bash
operator:x:11:0:operator:/root:/sbin/nologin
案例7:把/etc/passwd中以root開頭的行打印出來
[root@localhost ~]# awk -F: '/^root/' /etc/passwd
root:x:0:0:root:/root:/bin/bash
案例8:將/etc/passwd中匹配第三列和第五列的資料
[root@localhost ~]# awk -F: '{print $3,$5}' /etc/passwd
案例9:列印以root或者ntp開頭的行的解析器
[root@localhost ~]# awk -F: '/^root|^ntp/{print $7}' /etc/passwd
[root@localhost ~]# awk -F: '/^(root|ntp)/{print $7}' /etc/passwd

2.awk的工作原理

(1)awk會接收一行作為輸入,並將這一行賦給awk的內部變數$0,每一行也可稱為一個記錄,行的邊界是以換行符作為結束(表明:awk是一行一行的去處理文字的)
(2)然後,剛剛讀入的行被以:為分隔符分解成若干欄位(或域),每個欄位儲存在已編號的變數中,編號從$1開始,最多達100個欄位
注意:如果未指定行分隔符,awk將使用內建變數FS的值作為預設的行分隔符,FS預設值為空格,如果說要指定分隔符,需要使用-F引數或者重新定義FS變數
(3)使用print函式列印,如果$1$3之間沒有逗號,它倆在輸出時將貼在一起,應該在$1,$3之間加逗號,該逗號與awk的內建變數OFS保持一致,OFS預設為空格,於是以空格為分隔符輸出$1和$3
我們可以指定:awk -F: 'BEGIN{OFS="-"}{print $1,$3}' /etc/passwd
(4)輸出之後,將從檔案中獲取另一行,然後覆蓋給$0,繼續(2)的步驟將該行內容分隔成欄位。。。繼續(3)的步驟,該過程一直持續到所有行處理完畢

簡潔版:
1、awk會讀取檔案的一行內容然後賦值給$0
2、然後awk會以-F指定的分隔符將該行切分成n段,最多可以達到100段,第一段給$1,第二段給$2,依次次類推
3、print輸出該行的第一段和第三段,逗號代表輸出分隔符,預設與-F保持一致
4、重複步驟1,2,3直到檔案內容讀完

3.awk中的變數

$0:一整行內容
NR:記錄號(行號),每處理完一條記錄,NR值加1
NF:以-F分隔符分隔的段數,$1,$2...$100
FS:輸入欄位分割符,預設空格
OFS:輸出欄位分隔符

案例1:輸出/etc/passwd中的所有內容包括行號。
awk -F: '{print NR,$0}' /etc/passwd

案例2:要求把第7行之後的內容輸出出來,包括行號
awk -F: 'NR>7{print NR,$0}' /etc/passwd

案例3:要求輸出第7行之後的內容且第14行之前的內容輸出出來,包含行號
awk -F: 'NR>7 && NR<14{print NR,$0}' /etc/passwd

案例4:由案例3,要求輸出每行的UID增加1
awk -F: 'NR>7 && NR<14{print $3,$3+1}' /etc/passwd

案例5:要求輸出倒數第3列
awk -F: '{print $(NF-2)}' /etc/passwd

案例6:要求不使用-F引數,以:分割,並輸出第3列和第5列
awk 'BEGIN{FS=":"}{print $5,$3}' /etc/passwd

案例7:要求實驗證明-F 和 FS的優先順序
awk -F/ 'BEGIN{FS=":"}{print $7,$3}' /etc/passwd
證明得出-F引數的優先順序小於FS變數的優先順序

案例8:要求以:分割,並輸出第3列和第5列,第三列和第五列之間使用+號分割
awk -F: 'BEGIN{OFS="+"}{print $3,$5}' /etc/passwd
注:所有的變數的定義都應該放在BEGIN裡面

4.格式化輸出

================print函式===================
date | awk '{print "月:",$2,"\n年:",$1}'
月: 09月
年: 2020年

awk -F: '{print "使用者名稱:",$1,"使用者id:",$3}' /etc/passwd

================printf函式===================
awk -F: '{printf "使用者名稱:%s 使用者id:%s\n",$1,$3}' /etc/passwd
awk -F: '{printf "|%-15s| %-10s| %-15s|\n", $1,$2,$3}' /etc/passwd

%s 字元型別
%d 數值型別
佔15格的字串
- 表示左對齊,預設是右對齊
printf預設不會在行尾自動換行,加\n

案例:要求輸出第1列和最後一列,排版整齊
awk -F: '{printf"%-16s %s\n",$1,$NF}' /etc/passwd

5.操作模式

1.正則模式 awk -F: '/^root/' /etc/passwd
2.比較模式 awk -F: 'NR > 7{print $0}' /etc/passwd
3.條件模式 awk -F: 'NR > 7{print $0}' /etc/passwd
4.算數運算 awk -F: '{print $3,$3+1}' /etc/passwd
5.範圍模式 awk -F: '/root/,/ftp/{print $1}' /etc/passwd

6.流程控制

if判斷
單分支 if () {}
雙分支 if () {} else {}
多分支 if(){} else if() {} else{}

案例1:列印奇數行的資料
awk -F: '{if(NR % 2){print NR,$0}}' /etc/passwd

案例2.列印偶數行的資料
awk -F: '{if(NR % 2==0){print NR,$0}}' /etc/passwd
awk -F: 'NR%2==0{print NR,$0}' /etc/passwd
注: 單分支的情況下是可以省略if,多分支情況下不能省略

案例3:要求打印出偶數行中的包含bash的行
awk -F: '/bash/{if(NR%2==0){print NR,$0}}' /etc/passwd

案例4:要求在奇數行前輸出奇數,偶數行前輸出偶數
awk -F: '{if(NR%2){printf "奇數行:%s\n",$0}else{printf "偶數行:%s\n",$0}}' /etc/passwd

案例5:在前7行前加7, 前14行前加14,其他原樣輸出
awk -F: '{if(NR<=7){printf "7 %s \n",$0}else if (NR<=14){printf "14 %s \n",$0}else{print $0}}' /etc/passwd
for迴圈
for (變數 in 陣列){語句}
for (變數;條件;表示式){語句}
知識儲備:
++:每次加1
--:每次減1
案例1:將/etc/nginx/nginx.conf中的所有的詞的個數
egrep -o "[a-zA-Z0-9]+" /etc/nginx/nginx.conf|awk '{arr[$1]++}END{for(i in arr){printf "%-20s %d\n",i,arr[i]}}'

案例2:要求統計以#開頭的行中包含的詞的個數
egrep '^ *#' /etc/fstab | egrep -o "[a-zA-Z0-9]+" | awk '{arr[$1]++}END{for(i in arr){printf "%-20s %d\n",i,arr[i]}}'

案例3:輸入一個檔案路徑,要求打印出它的數字許可權(不允許使用stat)
ll [路徑] | awk 'BEGIN{FS=""}{if($2=="r"){u=u+4} if($3=="w"){u=u+2} if($4=="x"){u=u+1} if($5=="r"){g=g+4} if($6=="w"){g=g+2} if($7=="x"){g=g+1} if($8=="r"){o=o+4} if($9=="w"){o=o+2} if($10=="x"){o=o+1}}END{print u,g,o}'