awk應用

 

 awk在CentOS操作系統中是一個軟鏈接,鏈接到gawk程序上的。awk主要是對文件的行進行操作,將一行按照指定的方式進行切割。

 

一、awk工作機制

  awk在處理文本流時,每一次會讀取文本流中的一行並對這一行按指定的分隔符進行分隔,分隔後可以對每一個字段進行處理,其中輸入的分隔符可以和輸出的分隔符不一樣,這些都是通過awk內置的變量來處理的。

wKiom1VhnWzREROAAA772MNnwuw135.bmp

 

二、awk命令運用

格式:awk [OPTIONS] 'program' FILE1 FILE2 ...

2.1 print

用法:print item1,item2,….

示例1:輸出/etc/passwd文件中的第1個字段和第3個字段的值

[root@node-3 ~]# awk -F: '{print $1,$3}'/etc/passwd
root 0
bin 1
daemon 2
adm 3

根據輸出結果進行分析:

(1)-F:用於指明輸入字段的分隔符

(2)每個item之間用逗號分隔,輸出時的分隔符爲空白字符;

(3)如果print在輸出時省略了item,將會輸出整行的內容

 

示例2:根據上示例的要求,進行以“Name:root,UID:0”的格式輸出

[root@node-3 ~]# awk -F: '{print"Name:"$1,",UID:"$3}' /etc/passwd
Name:root ,UID:0
Name:bin ,UID:1
Name:daemon ,UID:2

根據輸出結果進行分析:

(1)在各item中以“”引號的內容將會原樣的輸出

(2)數值會被隱式轉換爲字符串進行輸出

 

2.2 awk變量

  awk的變量有內建變量和自定義的變量,內建變量是awk事先就已經定義好了,直接使用變量名就可以了,自定義變量根據情況的需求進行定義。

2.2.1 自定義變量

格式:-v VAR_NAME=VALUE

示例:[root@node-3 ~]# awk -v file="abc""{print file}" /etc/passwd
abc
abc
abc

根據輸出結果進行分析:

(1)-v用於自定義變量,變量名區別大小寫,遵循變量的定義

(2)顯示變量的值直接寫上變量名

(3)示例中將輸出多次,次數是根據/etc/passwd的行數來決定的

 

2.2.2 內建變量

變量名說明
FS
輸入字段分隔符,默認爲空白;
RS輸入時的行分隔符,默認爲換行符;
OFS輸出時的字段分隔符,默認爲空白字符;
ORS輸出時的行分隔符,默認爲換行符;
NF當前行的字段數;
NR行數;命令後跟的所有文件將統一計數;
FNR行數,多個文件時,各文件單獨計數;
FILENAME當前正被awk讀取的文件的文件名;
ARGCawk命令行中的參數的個數;
ARGV數組,保存了命令行參數本身;

示例1:顯示/etc/passwd文件中以“:”和“/”分隔符的第1個字段和第7個字段,原文件如下:

[root@node-3 ~]# cat /etc/passwd
root:x:0:0:root:/root:/bin/bash
bin:x:1:1:bin:/bin:/sbin/nologin
daemon:x:2:2:daemon:/sbin:/sbin/nologin

 

[root@node-3 ~]# awk -v FS="[:/]"'{print $1,$7}' /etc/passwd
root root
bin bin
daemon sbin

根據輸出結果進行分析:

(1)-v:對變量進行賦值,包含內建變量和自定義變量;

(2)FS是awk的內建變量,表示指定字符之間的分隔符;

(3)FS的值要用雙引號引起來,如果要指定多個分隔直接寫在“[]”中即可。

 

示例2:測試文件如下,以“,”爲行結束符,輸出整行的內容,接着輸出第1字段、第3字段:

[root@node-3 ~]# cat awk.txt 
how are you , how old are  you ?
how old your , Yes are you ?
 
[root@node-3 ~]# awk -v RS=","'{print $0}' awk.txt 
how are you 
 howold are  you ?
how old your 
 Yesare you ?
[root@node-3 ~]# awk  -v FS=" " -v RS=","  '{print $1,$3}' awk.txt 
how you
how are
Yes you

根據輸出結果進行分析:

(1)RS改變了行結束符,默認的行結束符可以使用cat -A awk.txt查看。

(2)-v選項可以使用多次,每定義一個變量的值,要使用一次“-v”選項。

 

示例3:根據/etc/passwd文件中輸出第1字段和第3字段,格式爲“root:0”,原文件如下:

[root@node-3 ~]# cat /etc/passwd
root:x:0:0:root:/root:/bin/bash
bin:x:1:1:bin:/bin:/sbin/nologin
daemon:x:2:2:daemon:/sbin:/sbin/nologin

 

方法1:
[root@node-3 ~]# awk -F:  -v OFS=":" '{print $1,$3}'/etc/passwd
root:0
bin:1
daemon:2
方法2:
[root@node-3 ~]# awk -F:  '{print $1":"$3}' /etc/passwd
root:0
bin:1
daemon:2

根據輸出結果進行分析:

(1)-v OFS=”:”用於定義輸出字段之間的分隔符,默認爲空白字符

(2)方法2中的 pirnt $1”:”$3,中的雙引號中的內容會原樣的輸出,這就是字符串之間的連接

 

示例4:將示例3中的輸出結果以“,”會換行符。

[root@node-3 ~]# awk -F: -vORS="," '{print $1":"$3}' /etc/passwd
root:0,bin:1,daemon:2,[root@node-3 ~]#

根據輸出結果進行分析:

(1)ORS更改默認的換行符將以指定符號輸出

 

示例5:根據如下文件內容,輸出字段的個數,並顯示最後一個字段的內容

[root@node-3 ~]# cat awk.txt 
how are you , how old are  you ?
how old your , Yes are you ?
 
[root@node-3 ~]# awk '{print NF,$NF}'awk.txt 
9 ?
8 ?

根據輸出結果進行分析:

(1)NF使用顯示被分隔符分隔後的字段個數。

(2)$後面跟上一個數字用於顯示指定字段的內容,而NF是一個數字,替換後就是顯示最後一個字段。

 

示例6:顯示awk.txt和/etc/passwd文件行號

[root@node-3 ~]# awk '{print NR,$0}'awk.txt /etc/passwd
1 how are you , how old are  you ?
2 how old your , Yes are you ?
3 root:x:0:0:root:/root:/bin/bash
4 bin:x:1:1:bin:/bin:/sbin/nologin
5 daemon:x:2:2:daemon:/sbin:/sbin/nologin
 
[root@node-3 ~]# awk '{print FNR,$0}'awk.txt /etc/passwd
1 how are you , how old are  you ?
2 how old your , Yes are you ?
1 root:x:0:0:root:/root:/bin/bash
2 bin:x:1:1:bin:/bin:/sbin/nologin
3 daemon:x:2:2:daemon:/sbin:/sbin/nologin

根據輸出結果進行分析:

(1)awk後可以跟多個文件

(2)NR變量在對多個文件顯示行號時,後一個文件的行號是接着前一個文件的行號繼續增加顯示的

(3)FNR變量對多個文件是分別進行顯示行號

 

示例7:顯示awk當前正在處理的文件名

[root@node-3 ~]# awk '{print FNR,FILENAME}'awk.txt /etc/passwd
1 awk.txt
2 awk.txt
1 /etc/passwd
2 /etc/passwd
3 /etc/passwd

 

示例8:根據示例7顯示awk的參數個數及第2個參數的值

[root@node-3 ~]# awk '{printFNR,FILENAME,ARGC,ARGV[1]}' awk.txt /etc/passwd 
1 awk.txt 3 awk.txt
2 awk.txt 3 awk.txt
1 /etc/passwd 3 awk.txt
2 /etc/passwd 3 awk.txt
3 /etc/passwd 3 awk.txt

根據輸出結果進行分析:

(1)ARGC用於保存當前awk參數的個數

(2)ARGV是一個數組,保存的是當前數組每個參數的值,數組的Index號是從0開始編號的,ARGV[0]存放的是awk, ARGV[1]存放的是awk.txt, ARGV[2]存放的是/etc/passwd,ARGV[3]存放的是NULL。

 

2.3 printf

  printf用於格式化輸出,此風格類似於C語言中的格式化輸出信息,可以根據定義在指定的位置顯示字段信息及保留小數點後指定的位數等 。

格式:printf FORMAT,item1,item2,...

類型符號說明
格式符%c顯示字符的ASCII碼;
%d,%i顯示爲十進制整數;
%e,%E科學計數法顯示數值;
%f顯示爲浮點數;
%g,%G以科學計數法或浮點數格式顯示數值;
%s顯示爲字符串;
%u顯示無符號整數;
%%顯示%符號自身;
修飾符#[.#]左邊的#指用於指定顯示寬度;右邊的#指顯示精度;
+顯示數值符號
-左對齊,默認爲右對齊

注意:

(1) 必須提供FORMAT;

(2) 與print語句不同,printf不會自動換行,需要顯式指定換行符:\n

(3) FORMAT中需要分別爲後面的每個item指定一個格式符,否則item則無法顯示;

 

示例:將/etc/passwd文件進行格式化輸出

[root@node-3 ~]# awk -F: '{printf"%20s:%-10.5f:%s\n",$1,$3,$NF}' /etc/passwd
                root:0.00000   :/bin/bash
                 bin:1.00000   :/sbin/nologin
              daemon:2.00000   :/sbin/nologin
[root@node-3 ~]# awk -F: '{printf"%20s:%10.5f:%s\n",$1,$3,$NF}' /etc/passwd
 
                root:   0.00000:/bin/bash
                 bin:   1.00000:/sbin/nologin
              daemon:   2.00000:/sbin/nologin

根據輸出結果進行分析:

(1)%20s:輸出的是字符串,第1個字段的長度爲20,awk默認是右對齊

(2)%10.5f:輸出的是浮點型數值,長度是10,小點後面保留5位

(3)%-10.5f:其中的“-”表示左對齊

(4)\n:表示換行符

(5)FORMAT中除格式符和修飾符之外的其它符號或字符都將原樣的輸出

 

2.4 操作符

  awk的操作符非常的豐富,包含算術操作符、字符操作符、賦值操作符、比較操作符、模式匹配操作符、邏輯操作符、條件表達式等。

類型符號說明
算術操作符x+y, x-y, x*y, x/y, x^y, x%y,-x,+x加、減、乘、除、次方、模,負值、轉換爲數值
賦值操作符=, +=, -=, *=, /=, %=,++, --賦值、加後賦值、減後賦值、乘後賦值、除後賦值、取模後賦值、自增、自減
比較操作符>, >=, <, <=, ==, !=大於、大於等於、小於、小於等於、等於、不等於
模式匹配操作符

~,!~

是否能由右側指定的模式所匹配;是否不能由右側指定模式所匹配;

邏輯操作符&&,||與運算、或運算
條件條件式selector?if-true-expression:if-false-expression條件表達式

示例1:顯示/etc/passwd文件UID大於500的用戶

[root@node-3 ~]# awk -F: '$3>500{print$1,$3}' /etc/passwd
nfsnobody 65534
testuser 1000
centos 1001
user1 1002
gentoo 1003

 

示例2:顯示/etc/passwd文件中每行字段中包含有bash字符的行

[root@node-3 ~]# awk -F:'$0~"bash"{print $0}' /etc/passwd
root:x:0:0:root:/root:/bin/bash
bbs:x:496:493::/home/bbs:/bin/bash
testuser:x:1000:500::/home/testuser:/bin/bash
centos:x:1001:1001::/home/centos:/bin/bash
user1:x:1002:1002:chrootuser:/home/user1:/bin/bash
gentoo:x:1003:1003::/home/gentoo:/bin/bash
nginx:x:495:492::/home/nginx:/bin/bash

 

示例3:判斷用戶UID是否大於等於500,格式化顯示用戶名信息

[root@node-3 ~]# awk -F: '$3>=500?type="commonuser":type="system user"{printf "%20s:%s\n",$1,type }'/etc/passwd
……………省略…………………
           testuser:common user
            centos:common user
             user1:common user
             gentoo:common user
             nginx:system user

根據輸出結果進行分析:

(1)$3>=500?type="commonuser":type="system user":將/etc/passwd文件中以“:”爲分隔符第3段值取出來,如果UID大於等於500把變量type賦值systemuser,否則就把變量type賦值system user.

(2)使用格式化顯示用戶名和type變量的值

 

2.5 PATTERN

  在PATTERN中可以使用正則表達式,關係表達式,指定要處理的行範圍等等 。

PATTERN說明
Empty空模式,匹配所有行;
/Regular Expression/僅將ACTION應用於能夠被Regular Expression(正則表達式)所匹配到的行;
relational expression關係表達式,即結果爲“真”、“假”的表達式,或者其結果能類同於“真”或“假”的表達;一般來說,其結果爲非0數值或非空字符串即可類同爲“真”,否則,則類同爲“假”;
line ranges行範圍,類似sed或vim中的地址定界方式;
BEGIN在文件格式化操作開始之前事先執行的一次操作;通常用於輸出表頭或做出一個預處理操作;
END在文件格式操作完成之後,命令退出之前執行的一次操作;通常用於輸出表尾或做出清理操作;

 

示例1:在/etc/passwd文件中顯示以bash結尾的行

[root@node-3 ~]# awk -F: '/bash$/{print$0}' /etc/passwd
root:x:0:0:root:/root:/bin/bash
bbs:x:496:493::/home/bbs:/bin/bash
testuser:x:1000:500::/home/testuser:/bin/bash
centos:x:1001:1001::/home/centos:/bin/bash
user1:x:1002:1002:chrootuser:/home/user1:/bin/bash
gentoo:x:1003:1003::/home/gentoo:/bin/bash
nginx:x:495:492::/home/nginx:/bin/bash

 

示例2:在/etc/passwd文件中顯示UID大於500的用戶名

[root@node-3 ~]# awk -F: '$3>500{print$1}' /etc/passwd
nfsnobody
testuser
centos
user1
gentoo

 

示例3:統計/etc/passwd文件中所有UID的和

[root@node-3 ~]# awk 'BEGIN{FS=":";sum=0}{sum+=$3}END{print sum}' /etc/passwd
73318

根據輸出結果進行分析:

(1)BEGIN{FS=":";sum=0}:表示在awk在對行處理之前執行的動作,FS是指定字段的分隔符,sum是自定義的一個變量,用於累加所有UID的和

(2){sum+=$3}:就是在對每一行進行操作,這裏沒有使用print輸出信息,sum=sum+$3;

(3)END{print sum}:awk對文件中所有行處理完之後在執行END的語句

 

示例4:格式化輸出/etc/passwd文件中用戶和UID

[root@node-3 ~]# awk -F: 'BEGIN {printf"%15s:%-s\n","User","UID";print"================================="}{printf"%15s:%-s\n",$1,$3}END{print"================================";printf "%20s\n","ENDof file"}' /etc/passwd
          User:UID
=================================
          root:0
           bin:1
        daemon:2
           adm:3
            lp:4
          sync:5
…………………省略………………
         user1:1002
        gentoo:1003
         nginx:495
================================
        END of file


2.6 控制語句

  在awk控制語句中有if、while、do、for、switch、break、contiune、next等

2.6.1 if-else語句

格式:if (condition) {statements} [else{statements}]

 

示例1:在/etc/passwd文件中顯示UID大於500的用戶名

[root@node-3 ~]# awk -F:'{if($3>500){print $1,$3}}' /etc/passwd
nfsnobody 65534
testuser 1000
centos 1001
user1 1002
gentoo 1003

 

示例2:判斷/etc/inittab的字段數大於6的,以空格分隔的

[root@node-3 ~]# awk '{if (NF>6) {printNF,$0}}' /etc/inittab 
11 # inittab is only used by upstart forthe default runlevel.
12 # ADDING OTHER CONFIGURATION HERE WILLHAVE NO EFFECT ON YOUR SYSTEM.
7 # System initialization is started by/etc/init/rcS.conf
7 # Individual runlevels are started by/etc/init/rc.conf
9 # Terminal gettys are handled by/etc/init/tty.conf and /etc/init/serial.conf,
12 # For information on how to writeupstart event handlers, or how
8 # upstart works, see init(5), init(8),and initctl(8).
7 # Default runlevel. The runlevels usedare:
10 #  0 - halt (Do NOT set initdefault to this)
16 #  2 - Multiuser, without NFS (The same as 3, if you do not havenetworking)
10 #  6 - reboot (Do NOT set initdefault to this)

 

2.6.2 while循環

格式:while (condition) {statements}

 

示例:顯示字段字符數大於10的字符

[root@node-3 ~]# awk '{i=1;while(i<NF){if (length($i)>10) printf "%20s:%d\n",$i,length($i);i++}}'/etc/inittab 
      CONFIGURATION:13
     initialization:14
    Ctrl-Alt-Delete:15
 /etc/init/tty.conf:18
      configuration:13
        information:11
        initdefault:11
        initdefault:11

根據輸出結果進行分析:

(1)while用於在當前行的種字段之間進行循環。

(2)length()是awk的內置變量,用於測試字符在長度的

 

2.6.3 for循環

格式:for (expr1;expr2;expr3) {statements}

 

示例:顯示/etc/inittab文件中以空格爲分隔符,顯示每個字段的長度

[root@node-3 ~]# awk '{for(i=1;i<=NF;i++) {printf "%20s:%d\n",$i,length($i)}}' /etc/inittab 
                   #:1
                  inittab:7
                  is:2
                  only:4
                  used:4
                  by:2


2.6.4 bread 和countinue

break [n]:退出當前循環,n是一個數字,用於指定退出幾層循環;

continue:提前結束本輪循環而進入下一輪;

 

示例:顯示/etc/passwd每個字段的字符數小於10的,只要遇到大於10的就不在判斷後面的字段的字符數

[root@node-3 ~]# awk -F:'{for(i=1;i<=NF;i++){if(length($i)>10){break}else {printlength($i),$i}}}' /etc/passwd
4 root
1 x
1 0
1 0
4 root
5 /root
9 /bin/bash
3 bin
1 x
1 1
1 1

 

2.6.5 next

next用於提前結束對本行文本的處理,而提前進入下一行的處理操作;

 

示例:顯示/etc/passwd中UID是奇數的用戶名和UID

[root@node-3 ~]# awk -F: '{if($3%2==0)next;print $1,$3}' /etc/passwd
bin 1
adm 3
sync 5
halt 7
operator 11
gopher 13
nobody 99

 

2.7 數組

格式:array[index-expression]

  其中index-expression可以是任意字符,如果某數組元素事先不存在,則在引用時,awk會自動創建元素並將其值初始化爲空串,awk的數組下標是從1開始編號的。

如果要遍歷數組中的元素,則要使用for (var_name in array)

 

示例:統計當前系統上所有tcp連接的各種狀態的個數;

[root@node-3 ~]# netstat  -tan|awk '/^tcp/{count[$NF]++}END{for(i incount){print i,count[i]}}'
TIME_WAIT 4000
ESTABLISHED 2
LISTEN 8

 

示例:統計指定的web訪問日誌中各ip的資源訪問次數:

[root@node-3 ~]# awk '{ip[$1]++}END{for (iin ip){print i,ip[i]}}' /var/log/httpd/access_log
172.16.9.35 4016
172.16.9.7 186
172.16.9.9 153

 

2.8 函數

  在awk中函數有內建函數和用戶自定義函數兩種。

2.8.1 內建函數

函數名說明
rand()返回0至1之間的一個隨機數;
length([s])返回指定的字符串的長度;
sub(r,s[,t])基於r所表示的模式來匹配字符串t中的內容,將其第一次被匹配到的內容替換爲s所表示的字符串;
gsub(r,s[,t])基於r所表示的模式來匹配字符串t中的內容,將其所有被匹配到的內容均替換爲s所表示的字符串;
split(s,a[,r])以r爲分隔符去切割字符串s,並將切割後的結果保存至a表示的數組中;
substr(s,i[,n])從s所表示的字符串中取子串,取法:從i表示的位置開始,取n個字符;
systime()取當前系統時間,結果形式爲時間戳;

 

示例1:返回一個0至1之間的一個隨機數

[root@node-3 ~]# awk 'BEGIN {print rand()}'
0.237788

 

示例2:返回/etc/passwd文件中用戶名字符串的長度

[root@node-3 ~]# awk -F: '{print$1,length($1)}' /etc/passwd
root 4
bin 3
daemon 6
adm 3

 

示例3:將root用戶名中“oo”替換成大寫的“OO”

[root@node-3 ~]# awk -F:'/^root/{sub("oo","OO",$0);print $0}' /etc/passwd
rOOt:x:0:0:root:/root:/bin/bash

 

示例4:將以root用戶名爲行的全部“oo”替換成大寫的“OO”

[root@node-3 ~]# awk -F:'/^root/{gsub("oo","OO",$0);print $0}' /etc/passwd
rOOt:x:0:0:rOOt:/rOOt:/bin/bash

 

示例5:split函數指明字段的分隔符

[root@node-3 ~]# awk '{split($0,user,":");printuser[1]}' /etc/passwd
root
bin
daemon
adm


示例6:在/etc/passwd文件中默認shell是/bin/bash的用戶,從第7個字段中從4個字符開始取出3個字符

[root@node-3 ~]# awk -F:'/bash$/{char=substr($NF,4,3);printf "%s:%5s\n",$NF,char}'/etc/passwd
/bin/bash: n/b
/bin/bash: n/b
/bin/bash: n/b
/bin/bash: n/b
/bin/bash: n/b
/bin/bash: n/b
/bin/bash: n/b

如果想獲取更多的幫助請man awk.


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