Shell(1):awk
0、常用
1、第一列 awk '{print $1}' filename 2、前兩列(用空格分隔) awk '{print $1,$2}' filename 3、打印完第一列,然后打印第二列(無分隔) awk '{print $1 $2}' filename #2和3的區別在于,2的列與列輸出時會有間隔,3的列與列在輸出時直接拼在一塊 4. 最后一列 awk '{print $NF}'#$NF:最后一列的值;NF:列數 5、總行數 總列數: awk 'END{print NR}' filename awk 'END{print NF}' filename 總列數(由于行與行的列數可能不同) 因此這里輸出的是最后一行的列數 1、第一行 : awk 'NR==1{print}' filename 2. 第一行的1、2、3列 awk 'NR==1{print $1, $2, $3}' 3. 指定分隔符(這里以:分割) awk -F':' '{print $1}' 4、第5~9行,第1,2,3列 awk -F':' 'NR>=5 && NR<=9{print $1,$2,$3}' 5、第5~9行,全部列 awk -F':' 'NR>=5&&NR<=9{for(i=1;i<=NF;i++) printf("%s ",$i);printf("\n")} }' #注意這里的printf("\n")與前邊的printf在同一個大括號內, #前邊的大括號每行會循環NF次,而printf"\n"則每行執行一次,它和for循環用;分隔,是并列的,不參與循環 6、將5中的內容輸出到文件test1 awk -F':' 'NR>=5&&NR<=9{for(i=1;i<=NF;i++) printf("%s ",$i);printf("\n")} }' test | awk 'print > "test1"' 9. 超出范圍不報錯 ps -aux | grep watchdog | awk '{print $100}'
1、概述
awk是一種處理文本文件的語言,是一個強大的文本分析工具。
Linux中的指令輸出多是分列、分行的,例如常見的ll(列出路徑下的文件)
ll 總用量 68 -rw-r--r--. 1 root root 1077 8月 10 2023 fastcgi.conf -rw-r--r--. 1 root root 1077 8月 10 2023 fastcgi.conf.default -rw-r--r--. 1 root root 1007 8月 10 2023 fastcgi_params -rw-r--r--. 1 root root 1007 8月 10 2023 fastcgi_params.default -rw-r--r--. 1 root root 2837 8月 10 2023 koi-utf -rw-r--r--. 1 root root 2223 8月 10 2023 koi-win -rw-r--r--. 1 root root 5231 8月 10 2023 mime.types -rw-r--r--. 1 root root 5231 8月 10 2023 mime.types.default -rw-r--r--. 1 root root 2656 8月 10 2023 nginx.conf -rw-r--r--. 1 root root 2656 8月 10 2023 nginx.conf.default -rw-r--r--. 1 root root 636 8月 10 2023 scgi_params -rw-r--r--. 1 root root 636 8月 10 2023 scgi_params.default -rw-r--r--. 1 root root 664 8月 10 2023 uwsgi_params -rw-r--r--. 1 root root 664 8月 10 2023 uwsgi_params.default -rw-r--r--. 1 root root 3610 8月 10 2023 win-utf
如果想提取這些列中的某一列進行處理,就可以用awk:
ll | awk '{print $5}' 1077 1077 1007 1007 2837 2223 5231 5231 2656 2656 636 636 664 664 3610
這里相當于用awk提取出第五列。
從這里可以對awk的作用進行一個簡述,對那些按行列傳入的數據,可以對某一列進行一個統一的處理。
2、awk基本使用
1)用法
awk '條件1{動作1} 條件2{動作2}...' 文件
awk 參數1 變量1 參數2 變量2 '條件1 {動作1} 條件2 {動作2}' 文件/內容
說明
- awk必須有輸入文件或者標準輸入,也就是說要么在最后寫文件名,要么用管道|將要處理的內容送進來,不能單放一個awk '...'上來
awk '條件 {動作}' 文件名
#或 echo 輸出內容 | awk '條件 {動作}' - 如果要進行awk測試(也就是說不需要依賴輸入文件的數據),可以這樣寫:
echo | awk '測試內容'
2)條件
一般使用關系表達式:
- x > 10 判斷變量x是否大于10
- x == y 判斷變量x是否等于變量y
- A ~ B 判斷字符串A中是否包含能匹配B表達式的子字符串
- A !~ B 判斷字符串A中是否不包含能匹配B表達式的子字符串
3)動作:①格式化輸出printf;②流程控制語句
printf用法
printf '輸出類型輸出格式' 內容
輸出類型:以%開頭
輸出類型 |
說明 |
| %c | ASCII字符 |
| %s | 字符串(后邊內容中有幾個參數就要寫幾個%s) |
| %-ns | 字符串(-表示左對齊,n表示輸出幾個字符) |
| %-ni | 輸出整數,n代表輸出幾個數字 |
| %f | 小數點右邊的位數 |
| %m.nf | 浮點數,m代表全部位數,n代表小數位數 |
輸出特殊格式(換行、占位):以\開頭
輸出格式 |
說明 |
| \a | 輸出警告聲音 |
| \b | 輸出退格鍵 |
| \f | 清除屏幕 |
| \n | 換行 |
| \r | 回車 |
| \t | 水平輸出TAB |
| \v | 垂直輸出TAB |
內容
內容如果是個文件,則會按行輸出每行的處理結果
例子
①常規打印
[root@localhost ~]$ vi student.txt
ID Name php Linux MySQL Average
1 AAA 66 66 66 66
2 BBB 77 77 77 77
3 CCC 88 88 88 88
#printf格式輸出文件
[root@localhost ~]$ printf '%s\t %s\t %s\t %s\t %s\t %s\t \n’ $(cat student.txt)#printf '格式' 內容
#%s分別對應后面的參數,6列就寫6個
ID Name php Linux MySQL Average
1 AAA 66 66 66 66
2 BBB 77 77 77 77
3 CCC 88 88 88 88
②輸出到文件
echo | awk '{print "hello world!\n" >> "test"}'
三個注意點:
- awk必須要有輸入文件或者管道輸入項,如果不需要,可以寫出 echo | awk '...'的形式;
- 輸出到文件,這個文件名需要用雙引號""括起來;
- 輸出到文件,寫法為>>(追加)和>(覆蓋),即輸出重定向。
4)常用參數(放在awk之后)
- -F 指定輸入時用到的字段分隔符
- -v 自定義變量
- -f 從腳本中讀取awk命令
- -m 對val值設置內在限制
①用法:awk 參數1 變量1 參數2 變量2 '條件1 {動作1} 條件2 {動作2}' 文件/內容
②例子
awk -F':' -v ORS="," '{$1=$1;PRINT $0}' /etc/passwd
解釋:
分隔符-F為:
輸出結果分隔符(項與項之間)-v為ORS=",",
動作為將第一行賦值給第一行,打印每一行
內容為 /etc/passwd的每一行
③awk內置變量(-v后可以跟的內容)
awk內置變量 |
作用 |
| $0 | 目前awk讀入的整行數據 |
| $n | 目前讀入行的第n個字段(列) |
| NF | 當前行擁有的字段(列)數 |
| NR | 當前awk處理的是哪一行 |
| FS |
輸入文件的分隔符(和-F作用相同,-v FS=':'的作用就和-F ':'相同)。 默認的是任何空格,如果想要用其他分隔符(如":"),就需要用FS變量定義,寫法 -v FS=':' |
| ARGC | 命令行參數個數 |
| ARGV | 命令行參數數組 |
| FNR | 當前文件中的當前記錄數(對輸入文件起始為1) |
| OFMT | 數值的輸出格式(默認%.6g) |
| OFS | 輸出字段(列與列之間)的分隔符(默認空格) |
| ORS | 輸出記錄(行與行之間)的分隔符(默認換行符) |
| RS |
輸入記錄的分隔符(默認換行符) 這個變量的含義是,原文件中每條記錄之間的分隔符,默認情況下是一行為一條記錄,此時記錄之間的分隔符就是換行符 |
記錄:各行
字段:各列
補充:
如果有多個自定義變量,就要為每個變量配一個-v
#指定輸入列與列分隔符為:,輸出記錄(行與行)分隔符為,
awk -v FS=':' -v ORS="," '{$1=$1;PRINT $0}' /etc/passwd
5)awk條件
awk 參數1 變量1 參數2 變量2 '條件1 {動作1} 條件2 {動作2}' 文件/內容
條件類型 |
條件 |
說明 |
| awk保留字 | BEGIN |
在awk程序開始時,尚未讀取任何數據之前執行。 BEGIN后的動作只在程序開始時執行一次。 |
| END |
在awk程序處理完所有數據,即將結束時執行。 END后的動作只在程序結束時執行一次。 |
|
| 關系運算符 | > | |
| < | ||
| >= | ||
| <= | ||
| == | ||
| != | ||
| A~B | A中包含B的子字符串 | |
| A!~B | A中不包含B的子字符串 | |
| 正則表達式 | /正則/ |
①BEGIN
BEGIN是awk保留字,是一種特殊的條件類型。BEGIN的執行時機是“awk程序一開始,尚未讀取任何數據之前執行”。
BEGIN定義的動作只能被執行一次(執行一次意思是不再像普通語句那樣對每行都循環執行,而是在所有行之前執行一次就結束):
awk 'BEGIN{printf "This is a transcript \n" } {printf $2 "\t" $6 "\n"}’ student.txt
#awk命令只要檢測不到完整的單引號不會執行,所以這個命令的換行不用加入“|”,就是一行命令
#這里定義了兩個動作
#第一個動作使用BEGIN條件,所以會在讀入文件數據前打印“這是一張成績單”(只會執行一次)
#第二個動作會打印文件的第二字段和第六字段
②END
也是awk保留字,但和BEGIN相反。END是awk程序處理完所有數據,即將結束時執行一次(不管這個END及其后的語句放在哪里,都是在最后一行執行完畢后執行):
awk 'END{printf "The End \n"} {printf $2 "\t" $6 "\n"}’ student.txt
#在輸出結尾輸入“The End”,這并不是文檔本身的內容,而且只會執行一次
③關系運算符
例①平均成績大于等于87分的學員是誰
cat student.txt | grep -v Name | awk '$6 >= 87 {printf $2 "\n"}'
#使用cat輸出文件內容,用grep取反包含“Name”的行
#判斷第六字段(平均成績)大于等于87分的行,如果判斷式成立,則打第六列(學員名$2)
加入條件之后,只有條件成立,動作才會執行。通過這個例子可以發現:awk雖然是列提取指令,但是要按行來讀入。它的執行過程如下:
- 有BEGIN條件,先執行BEGIN定義的動作;
- 如果沒有BEGIN條件,則讀入第一行,把第一行的數據依次賦予$0、$1、$2等變量。其中$0代表該行整體數據,$1代表第一字段,$2代表第二字段;
- 根據條件判斷動作是否執行。如果條件符合,則執行;否則讀入下一行數據。如果沒有條件,則每行都執行動作。
- 讀入下一行數據,重復上述步驟。
例②查找Sc用戶的平均成績
awk '$2 ~ /Sc/ {printf $6 "\n"}' student.txt
#如果第二字段中輸入包含有“Sc”字符,則打印第六字段數據
85.66
在awk中,使用"http://"包含的字符串,awk命令才會查找。也就是說字符串必須用"http://"包含,awk命令才能正確識別。(如上文的/Sc/)
④正則表達式
如果要讓awk識別字符串,必須用"http://"包含,
例1
awk '/Liming/ {print}’student.txt
#打印Liming的成績
例2:使用df命令查看分區使用情況,如何只想查看真正的系統分區的使用情況,而不想查看光盤和臨時分區的使用情況:
df -h | awk '/sda[O-9]/ {printf $1 "\t" $5 "\n"}’
#查詢包含有sda數字的行,并打印第一字段和第五字段
6)awk常用實例統計
awk 參數1 變量1 參數2 變量2 '條件1 {動作1} 條件2 {動作2}' 文件/內容
1、第一列
awk '{print $1}' filename
2、前兩列(用空格分隔)
awk '{print $1,$2}' filename
3、打印完第一列,然后打印第二列(無分隔)
awk '{print $1 $2}' filename
#2和3的區別在于,2的列與列輸出時會有間隔,3的列與列在輸出時直接拼在一塊
4. 最后一列
awk '{print $NF}'#$NF:最后一列的值;NF:列數
5、總行數 總列數:
awk 'END{print NR}' filename
awk 'END{print NF}' filename
總列數(由于行與行的列數可能不同)
因此這里輸出的是最后一行的列數
1、第一行 :
awk 'NR==1{print}' filename
2. 第一行的1、2、3列
awk 'NR==1{print $1, $2, $3}'
3. 指定分隔符(這里以:分割)
awk -F':' '{print $1}'
4、第5~9行,第1,2,3列
awk -F':' 'NR>=5 && NR<=9{print $1,$2,$3}'
5、第5~9行,全部列
awk -F':' 'NR>=5&&NR<=9{for(i=1;i<=NF;i++) printf("%s ",$i);printf("\n")} }'
#注意這里的printf("\n")與前邊的printf在同一個大括號內,
#前邊的大括號每行會循環NF次,而printf"\n"則每行執行一次,它和for循環用;分隔,是并列的,不參與循環
6、將5中的內容輸出到文件test1
awk -F':' 'NR>=5&&NR<=9{for(i=1;i<=NF;i++) printf("%s ",$i);printf("\n")} }' test
| awk 'print > "test1"'
9. 超出范圍不報錯
ps -aux | grep watchdog | awk '{print $100}'
7)awk定義和調用變量(放在動作{}塊中)
awk 參數1 變量1 參數2 變量2 '條件1 {動作1} 條件2 {動作2}' 文件/內容
假設我想統計PHP成績的總分,可以寫為:
[root@localhost ~]$ awk 'NR==2 {php1=$3}
NR==3 {php2=$3}
NR==4 {php3=$3;total=phpl+php2+php3;print "total php is " total}' student.txt
#統計PHIP成績的總分
對這個命令的解釋:
-
'NR==2 {php1=$3}':如果輸入數據是第二行(第一行是標題行),就把第二行的第三字段的值賦予變量php1;
-
'NR==3 {PHP2=$3}':同上
-
'NR==4 {php3=$3;total=php1+php2+php3;print "total php is " total}' student.txt:如果輸入數據是第四行,就把第四行第三字段的值賦予php3,之后定義變量total的值為"php1+php2+php3",然后輸出"total php is",后邊加上變量total的值。
在awk編程中,因為命令語句很長,在輸入格式時需要注意的內容:
- 多個條件 {動作}(即上文的NR==2 {...} 與 NR==3 {...})可以用空格分割,也可以用回車分割;
- 在一個動作(即上段代碼的{...}部分)中,如果需要執行多個命令(即上文的php3=$3;total=...;),需要用";"分割,或者用回車分割;
- 在awk中,變量的賦值和調用都不需要加入$符(只有在調用某行的哪列時才會用到$n);(有點類似Python的語法)
8)流程控制(用if的話要放在動作塊{}中,不用if就直接寫成相應條件)
awk 參數1 變量1 參數2 變量2 '條件1 {動作1} 條件2 {動作2}' 文件/內容
之前所說awk用法:awk '條件1{動作1} 條件2{動作2}...' 文件
這里的流程控制是放在動作中(即大括號{}內)的
awk '{if (NR>=2) {if ($4>60) printf $2 "is a good man!\n"}}' student.txt
#程序中有兩個if判斷,第一個判斷行號大于2,第二個判斷Linux成績大于90分
Liming is a good man !
Sc is a good man !
注意
awk{動作}中的if判斷語句,完全可以利用awk自帶的條件來取代,剛剛的腳本可以寫作:
awk ’NR>=2 {test=$4}
test>90 {printf $2 "is a good man! \n"}’ student.txt
#先判斷行號如果大于2,就把第四字段賦予變量test
#在判斷如果test的值大于90分,就打印好男人
Liming is a good man!
Sc is a good man!
8)awk函數
定義(在動作塊{}中)
function 函數名 (參數列表) {
函數體
}
#實際寫法
awk 'function 函數名(參數列表){
函數體
}
{調用該函數}
' 文件/內容
例子
#定義函數test,包含兩個參數,函數體的內容是輸出這兩個參數的值
awk 'function test(a,b) { printf a "\t" b "\n"}
{ test($2,$6) } ' student.txt
#調用函數test,并向兩個參數傳遞值。
Name Average
AAA 87.66
BBB 85.66
CCC 91.66
9)awk調用外部腳本文件
對于小的單行程序而言,將腳本作為命令行自變量傳遞給awk是非常簡單的,而對于多行程序就比較難以處理。當程序是多行時,使用外部腳本是很適合的。
首先在外部文件中寫好腳本,然后可以使用awk的-f選項,使其讀入腳本并且執行。
例子
首先寫好一個awk腳本
vi pass.awk
BEGIN {FS=":"}
{ print $1 "\t" $3}
然后可以使用"-f"來調用這個腳本:
[root@localhost ~]$ awk -f pass.awk /etc/passwd
rooto
bin1
daemon2
…省略部分輸出…

浙公網安備 33010602011771號