linux awk命令詳解


詳細介紹AWK的文章,推薦去朱雙印的個人博客,10分好評的個人博客,傳送門

 

本文章僅為個人精簡參考使用,不適合初學者,詳細的介紹文章,請用以上的傳送門

 

也可以稍微參考一下博客園:https://www.cnblogs.com/isykw/p/6258781.html

也可以參考CSDN https://blog.csdn.net/sunchengquan/article/details/80276842

本文包括

  • AWK簡介
  • awk基本語法
  • awk常用命令選項
  • awk的幾種模式
  • awk的內置變量
  • awk設置定義變量
  • awk模式的定義,空模式,關系運算模式,BEGIN模式,END模式,正則表達式模式
  • awk 在用 {x,y} 這種正則時,需要加參數
  • awk 支持if else, for ,while等控制語句
  • awk 計算日志中ip的數量
  • awk 把兩個文件內的指定列,合並成一個文件
  • awk編程,善用FNR NR
  • awk數學運算
  • awk 生成隨機數(利用awk的自帶函數)
  • awk中使用shell的環境變量

AWK簡介

awk是由Alfred Aho 、Peter Weinberger 和 Brian Kernighan這三個人創造的,awk由這個三個人的姓氏的首個字母組成。

awk早期是在unix上實現的,所以,我們現在在linux的所使用的awk其實是gawk,也就是GNU awk,簡稱為gawk,awk還有一個版本,New awk,簡稱為nawk,但是linux中最常用的還是gawk。

awk其實是一門編程語言,它支持條件判斷、數組、循環等功能。所以,我們也可以把awk理解成一個腳本語言解釋器。

awk  更適合格式化文本,以文件的行為處理單位的,對文本進行較復雜格式處理

AWK基礎

基本語法如下

awk [options] 'Pattern{Action}' file
awk '{ 

     BEGIN{stat1} 
     BEGIN{stat2} 
     pattern1{action1} 
     pattern2{action2} 
     ... 
     patternn{actionn} 
     {默認動作,無條件,始終執行} 

     END{stat1} 
     END{stat2} 
}'

 

常用命令選項

-F 指定輸入分隔符,fs可以是字符串或正則表達式,如 -F ':' , 默認的隔符是空格

-v var=value -v是一種選項,var是一個變量的名稱,value是一個變量的值,有很多內置的變量名稱

-v FS=':' 指定輸入分隔符為: 和 -F 類似

-v OFS='###' 指定 輸出分隔符 ,默認輸出分隔符為空格,可以換成任意的輸出分割符
-f scripfile 從腳本文件中讀取awk命令

 

awk命令插入一個文件,並使awk程序可執行,然后awk命令解釋器作為腳本的首行,一遍通過鍵入腳本名稱來調用。
相當於shell腳本首行的:#!/bin/sh
可以換成:#!/bin/awk

如果只是顯示/etc/passwd的賬戶
#cat /etc/passwd |awk  -F ':'  '{print $1}' root daemon bin sys

 

AWK 包含兩種特殊的模式:BEGIN 和 END。

BEGIN 模式指定了處理文本之前需要執行的操作:

END 模式指定了處理完所有行之后所需要執行的操作:

以下實例展示了-v FS 指定輸入分隔符 和 -v OFS 指定輸出分隔符 指定BEGIN 和 END

awk 處理 /etc/passwd  獲取 $1,$7的數據

而賬戶與shell之間以'++++'分割,

而且在第一行添加文字 "name,shell",

在最后一行添加"blue,/bin/nosh"。

[root@cnblogs ~]# cat /etc/passwd |awk  -v FS=':' -v OFS="++++" 'BEGIN {print "name,shell"}  {print $1,$7} END {print "blue,/bin/nosh"}'
name,shell
root++++/bin/bash
bin++++/sbin/nologin
daemon++++/sbin/nologin
...
... blue,
/bin/nosh

 

awk內置變量

awk有許多內置變量用來設置環境信息,這些變量可以被改變,下面給出了最常用的一些變量。

ARGC               命令行參數個數
ARGV               ARGV內置變量表示的是一個數組,這個數組中保存的是命令行所給定的參數。這樣解釋還是很模糊,不容易理解,我們來看看示例。
ENVIRON            支持隊列中系統環境變量的使用
FILENAME           awk瀏覽的文件名
FNR                各文件分別記錄的行號
FS                 FS: field separator設置輸入域分隔符,等價於命令行 -F選項
NF                 列數,number of the field,當前處理行的總列數(被分成幾列)
NR                 行數,number of the row,當前處理文本行的行號
OFS                OFS:output field separator 輸出字段分隔符, 默認為空白字符
ORS                ORS:output row separator 輸出記錄分隔符(輸出換行符),輸出時用指定符號代替換行符
RS                 RS:row separator 輸入記錄分隔符(輸入換行符), 指定輸入時的換行符

除了內置變量,也可以定義自定義變量

有兩種定義方法

方法一:-v varname=value  變量名區分字符大小寫。

方法二:在program中直接定義。

[root@cnblogs ~]# awk -v myVAR="testVAR" 'BEGIN{print myVAR}'
testVAR
[root@cnblogs ~]# awk 'BEGIN{myVAR="testVAR";print myVAR}'
testVAR

也可以一次定義多個,如

[root@cnblogs ~]# awk 'BEGIN{myVAR1="testVAR1";myVAR2="testVAR2";print myVAR1,myVAR2}'
testVAR1 testVAR2

 

統計/etc/passwd:文件名,每行的行號,每行的列數,對應的完整行內容:

[root@cnblogs ~]#  awk  -F ':'  '{print "filename:" FILENAME ",linenumber:" NR ",columns:" NF ",linecontent:"$0}' /etc/passwd
filename:/etc/passwd,linenumber:1,columns:7,linecontent:root:x:0:0:root:/root:/bin/bash
filename:/etc/passwd,linenumber:2,columns:7,linecontent:bin:x:1:1:bin:/bin:/sbin/nologin
filename:/etc/passwd,linenumber:3,columns:7,linecontent:daemon:x:2:2:daemon:/sbin:/sbin/nologin
filename:/etc/passwd,linenumber:4,columns:7,linecontent:adm:x:3:4:adm:/var/adm:/sbin/nologin
filename:/etc/passwd,linenumber:5,columns:7,linecontent:lp:x:4:7:lp:/var/spool/lpd:/sbin/nologin
filename:/etc/passwd,linenumber:6,columns:7,linecontent:sync:x:5:0:sync:/sbin:/bin/sync
filename:/etc/passwd,linenumber:7,columns:7,linecontent:shutdown:x:6:0:shutdown:/sbin:/sbin/shutdown

使用printf替代print,可以讓代碼更加簡潔,易讀

[root@cnblogs ~]# awk  -F ':'  '{printf("filename:%10s,linenumber:%s,columns:%s,linecontent:%s\n",FILENAME,NR,NF,$0)}' /etc/passwd
filename:/etc/passwd,linenumber:1,columns:7,linecontent:root:x:0:0:root:/root:/bin/bash
filename:/etc/passwd,linenumber:2,columns:7,linecontent:bin:x:1:1:bin:/bin:/sbin/nologin
filename:/etc/passwd,linenumber:3,columns:7,linecontent:daemon:x:2:2:daemon:/sbin:/sbin/nologin
filename:/etc/passwd,linenumber:4,columns:7,linecontent:adm:x:3:4:adm:/var/adm:/sbin/nologin
filename:/etc/passwd,linenumber:5,columns:7,linecontent:lp:x:4:7:lp:/var/spool/lpd:/sbin/nologin
filename:/etc/passwd,linenumber:6,columns:7,linecontent:sync:x:5:0:sync:/sbin:/bin/sync
filename:/etc/passwd,linenumber:7,columns:7,linecontent:shutdown:x:6:0:shutdown:/sbin:/sbin/shutdown

AWK模式的概念就是條件

"模式"這個詞聽上去文縐縐的,不是特別容易理解,那么我們換一種說法,我們把"模式"換成"條件",可能更容易理解,那么"條件"是什么意思呢?我們知道,awk是逐行處理文本的,也就是說,awk會先處理完當前行,再處理下一行,如果我們不指定任何"條件",awk會一行一行的處理文本中的每一行,如果我們指定了"條件",只有滿足"條件"的行才會被處理,不滿足"條件"的行就不會被處理。這樣說是不是比剛才好理解一點了呢?這其實就是awk中的"模式"。

再啰嗦一遍,當awk進行逐行處理的時候,會把pattern(模式)作為條件,判斷將要被處理的行是否滿足條件,是否能跟"模式"進行匹配,如果匹配,則處理,如果不匹配,則不進行處理。

 

以下是AWK模式的示例 NF=2 或者 NF>2 是條件,也就是模式

[root@cnblogs ~]# awk 'NF==2 {print $0}' /etc/passwd
ftp:x:14:50:FTP User:/var/ftp:/sbin/nologin
sshd:x:74:74:Privilege-separated SSH:/var/empty/sshd:/sbin/nologin
nscd:x:28:28:NSCD Daemon:/:/sbin/nologin

[root@cnblogs ~]# awk 'NF>2 {print $0}' /etc/passwd
systemd-network:x:192:192:systemd Network Management:/:/sbin/nologin
dbus:x:81:81:System message bus:/:/sbin/nologin
polkitd:x:999:998:User for polkitd:/:/sbin/nologin

 

AWK支持正則表達式匹配

 

 

 

 

 

 

 

 

 

 

 

 

 

 

除此之外,還要注意以下兩點

1、當在awk命令中使用正則模式時,使用到的正則用法屬於"擴展正則表達式"。

2、當使用 {x,y} 這種次數匹配的正則表達式時,需要配合--posix選項或者--re-interval選項。

 

 

 

 

 

awk的"模式(Pattern)",

空模式 沒有條件,每行都處理

關系運算模式 根據條件,處理符合條件的行

BEGIN 模式

END 模式

正則模式

 

AWK支持"if...else if...else"這樣的"控制語句"

 

 

 

 

 

 AWK支持for 循環,while  循環,continue,break,do ... while 循環

詳細請參考,朱雙印的博客:http://www.zsythink.net/archives/2062

#for循環語法格式1
for(初始化; 布爾表達式; 更新) {
//代碼語句
}
 
#for循環語法格式2
for(變量 in 數組) {
//代碼語句
}
 
#while循環語法
while( 布爾表達式 ) {
//代碼語句
}
 
#do...while循環語法
do {
//代碼語句
}while(條件)

 

 

 

 

 

 

 

 

為了方便判斷和閱讀,最好將多個語句用{}括起來。awk分支結構允許嵌套,其格式為:

示例:

awk 'BEGIN{
test=100;
if(test>90){
print "very good"
}
else if(test>60){
print "good"
}
else{
print "no pass"
}
}'

very good

 

自定義變量用; 分號結尾


while語句
示例:

awk 'BEGIN{
test=100;
total=0;
while(i<=test){
total+=i;
i++;
}
print total;
}'
5050

 

 

 


上圖中,我們使用了一個空模式,一個END模式。

 

 

 

 

 

如下示例,計算人名出現的次數

awk '{for (i=1;i<=NF;i++) {count[$i]++}} END{for(j in count){print j,count[j]}}' test4

 

 

 

 以下示例得到小於100的隨機數,使用了rand() 和 srand(),int() 函數

用srand()是因為,如果只使用rand(),第一次的數值不會變化,每次都是一樣的隨機數

[root@jenkins ~]# awk 'BEGIN{srand();print rand()}'
0.0698597
[root@jenkins ~]# awk 'BEGIN{srand();print 100*rand()}'
79.413
[root@jenkins ~]# awk 'BEGIN{srand();print int(100*rand())}'
73
[root@jenkins ~]# 

更多awk函數用法,請參考:

http://www.zsythink.net/archives/2113

https://www.cnblogs.com/isykw/p/6258781.html

 

按照列合並兩個文件

[root@cnblogs ~]# cat a
1 2
1 2
1 2
1 2
1 2
[root@cnblogs ~]# cat b
3 4
3 4
3 4
3 4
3 4
[root@cnblogs ~]# awk '{if(FNR==NR) {d[FNR]=$0}} {if(FNR!=NR){print d[FNR],$0}}' a b
1 2 3 4
1 2 3 4
1 2 3 4
1 2 3 4
1 2 3 4
[root@cnblogs ~]# awk '{if(FNR==NR) {d[FNR]=$1}} {if(FNR!=NR){print d[FNR],$2}}' a b
1 4
1 4
1 4
1 4
1 4
[root@cnblogs ~]# awk 'FNR==NR {x[FNR]=$0} FNR!=NR{print x[FNR],$0}' a b
1 2 3 4
1 2 3 4
1 2 3 4
1 2 3 4
1 2 3 4
[root@cnblogs ~]# 

 

a和b 有相同的列,把相同的列結合在一起

[root@cnblogs ~]# cat a
116 t1
117 t2
118 t3
[root@cnblogs ~]# cat b
116 1000
117 1500
118 800
[root@cnblogs ~]#  awk 'NR==FNR{a[$1]=$2}NR!=FNR{print a[$1],$2}'  a b
t1 1000
t2 1500
t3 800
[root@cnblogs ~]# awk '{print NR ,FNR ,$1,$2}' a b
1 1 116 t1
2 2 117 t2
3 3 118 t3
4 1 116 1000
5 2 117 1500
6 3 118 800

 awk數學運算示例

求1除以3結果保留一位小數,並且用%號表示數值

[root@cnblogs ~]# t1=1
[root@cnblogs ~]# t2=3
[root@cnblogs ~]# awk 'BEGIN{printf "%.1f%\n",("'$t1'"/"'$t2'")*100}'
33.3%
[root@cnblogs ~]# 

 

awk中使用shell的環境變量

 

第一種方法,使用-v ,定義變量可以引用變量

 

[root@cnblogs ~]# abc=66666
[root@cnblogs ~]# awk -v myVAR="$abc" 'BEGIN{print myVAR}'
66666

 

 

[root@cnblogs ~]# var="test"
[root@cnblogs ~]# awk -v var="$var" 'BEGIN{print var}'
test

 第二種方法,在awk中直接引用,使用字符串變量 ,

注意使用前格式必須是先用單引號括住再用雙引號括住,如:
"
'$var'"
如果變量中含有空格或者特殊符號,需要如下
"'"$var"'"

如果不是用腳本文件方式執行,直接在shell里執行,需要先用export var=test 導出為環境變量,

這樣其后的awk子進程才會有該變量。

 

[root@cnblogs ~]# var="test"
[root@cnblogs ~]# awk 'BEGIN{print "'$var'"}'
test

 

[root@cnblogs ~]# var="this is a test"
[root@cnblogs ~]# awk 'BEGIN{print "'"$var"'"}'
this is a test
[root@cnblogs ~]# 
[root@cnblogs ~]# export var="this is a test"
[root@cnblogs ~]# awk 'BEGIN{print "'"$var"'"}'
this is a test
[root@cnblogs ~]# 

 

所有IP的連接數統計

awk 'BEGIN{while("netstat -an"|getline){if( $5 ~ /[1-255]/){split($5,t1,":");tarr[t1[1]]++;}}for(k in tarr){print k,tarr[k] | "sort -r -n -k2";}};'

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM