文本三劍客之AWK詳解

文本三劍客之AWK

awk簡介


            AWK是一種優良的文本處理工具。它不僅是 Linux中也是任何環境中現有的功能最強大的數據處理引擎之一。這種編程及數據操作語言(其名稱得自於它的創始人 Alfred Aho 、Peter Weinberger 和 Brian Kernighan 姓氏的首個字母)的最大功能取決於一個人所擁有的知識。AWK 提供了極其強大的功能:可以進行樣式裝入、流控制、數學運算符進程控制語句甚至於內置的變量和函數。它具備了一個完整的語言所應具有的幾乎所有精美特性。實際上 AWK 的確擁有自己的語言:AWK 程序設計語言, 三位創建者已將它正式定義爲“樣式掃描和處理語言”。它允許您創建簡短的程序,這些程序讀取輸入文件、爲數據排序、處理數據、對輸入執行計算以及生成報表,還有無數其他的功能。

            awk是一個強大的文本分析工具,與grep(查找)、sed(編輯)一併稱爲“文本處理三劍客”。awk最強大的功能是對數據分析並生成報告。

            awk有3個不同版本: awk、nawk和gawk,未作特別說明,一般指gawk,gawk是AWK的GNU版本。

工作原理


第一步:執行BEGIN{action;… }語句塊中的語句 

第二步:從文件或標準輸入(stdin)讀取一行,然後執行pattern{ action;… }語句塊,它逐行掃描文件,從第一行到最後一行重複這 個過程,直到文件全部被讀取完畢。 

第三步:當讀至輸入流末尾時,執行END{action;…}語句塊 

            BEGIN語句塊在awk開始從輸入流中讀取行之前被執行,這是一個 可選的語句塊,比如變量初始化、打印輸出表格的表頭等語句通常 可以寫在BEGIN語句塊中 

            END語句塊在awk從輸入流中讀取完所有的行之後即被執行,比如 打印所有行的分析結果這類信息彙總都是在END語句塊中完成,它 也是一個可選語句塊

            pattern語句塊中的通用命令是最重要的部分,也是可選的。如果 沒有提供pattern語句塊,則默認執行{ print },即打印每一個讀取 到的行,awk讀取的每一行都會執行該語句塊

            

     分割符、域和記錄 

            awk執行時,由分隔符分隔的字段(域)標記$1,$2..$n稱 爲域標識。$0爲所有域,注意:和shell中變量$符含義不同 

            文件的每一行稱爲記錄

            省略action,則默認執行 print $0 的操作


步驟

  1. 執行BEGIN{action;…}
    BEGIN在輸入之前執行,通常用來打印表頭,變量初始化。

  2. 讀取,執行pattern{action;…}
    默認執行{ print }

  3. 執行END{action;…}
    讀取到打印結束後執行,通常用作分析結果,信息彙總


AWK語法基本格式:


基本格式:awk [options] 'program' file… 

選項[options]: 

        -F 指明輸入時用到的字段分隔符 

        -v var=value: 自定義變量

        -f:調用awk腳本

program:pattern{action statements;..}

    語句之間用分號分割

pattern和action: 

pattern:部分決定動作語句何時觸發及觸發事件 BEGIN,END  (觸發條件)

        action statements:對數據進行處理,放在{}內指明 print, printf  (對數據處理動作)

        program通常是被單引號或雙引號中


知識點整理


1、print

 要點: 

(1) 逗號分隔符 

(2) 輸出的各item可以字符串,也可以是數值;當前記錄的字段、 變量或awk的表達式

(3) 如省略item,相當於print $0 


 示例: 


[root@centos7 ~]# tail -3 /etc/fstab #源文件
UUID=0cd9ec5d-a77e-46f4-b218-19d914a5ed1e /app xfs defaults 0 0
UUID=3535b5f0-7b38-4cc9-a099-551fa388392c /boot xfs defaults 0 0
UUID=c424d9be-be2c-4e7c-a007-1af750d9310b swap swap defaults 0 0

[root@centos7 ~]# tail -3 /etc/fstab |awk '{print}'  
UUID=0cd9ec5d-a77e-46f4-b218-19d914a5ed1e /app xfs defaults 0 0
UUID=3535b5f0-7b38-4cc9-a099-551fa388392c /boot xfs defaults 0 0
UUID=c424d9be-be2c-4e7c-a007-1af750d9310b swap swap defaults 0 0
[root@centos7 ~]# tail -3 /etc/fstab |awk '{print "wang"}'
wang
wang
wang

[root@centos7 ~]# tail -3 /etc/fstab |awk '{print $0}'
UUID=0cd9ec5d-a77e-46f4-b218-19d914a5ed1e /app xfs defaults 0 0
UUID=3535b5f0-7b38-4cc9-a099-551fa388392c /boot xfs defaults 0 0
UUID=c424d9be-be2c-4e7c-a007-1af750d9310b swap swap defaults 0 0
[root@centos7 ~]# tail -3 /etc/fstab |awk '{print $2$4}'
/appdefaults
/bootdefaults
swapdefaults、

[root@centos7 ~]# tail -3 /etc/fstab |awk '{print $2,$4}'
/app defaults
/boot defaults
swap defaults

[root@centos7 ~]# tail -3 /etc/fstab |awk '{print $2"\t"$4}'
/appdefaults
/bootdefaults
swapdefaults


2、變量

    2.1    內建命令

    FS:輸入字段分隔符,默認爲空白字符 

~]# awk -v FS=: '{print $1,FS,$3}' /etc/passwd
~]# awk -F":" '{print $1,$3}' /etc/passwd

    OFS:輸出字段分隔符,默認爲空白字符 

 ~]# awk -v FS=":" -v OFS=: '{print $1,$3,$7 }' /etc/passwd

    RS:輸入記錄分隔符,指定輸入時的換行符,原換行符仍有效

~]# awk -v RS=''^C{print}' /etc/passwd

    ORS:輸出記錄分隔符,輸出時用指定符號代替換行符

~]#awk -v RS=' ' -v ORS=' ' ‘{print }’ /etc/passwd

    ARGC:命令行參數的個數

~]# awk -F: ‘{print NF}’ /etc/fstab,引用內置變量不用$ 
~]# awk -F:  '{print $(NF-1)}'  /etc/passwd

    ARGV:數組,保存命令行給定的各參數

~]# [root@centos7 ~]# awk -F: '{print NF}' /etc/passwd 
7
7
~]# awk -F: '{print $(NF-1)}' /etc/passwd
/root
/bin


    NF:字段數量

~]#
 ~]# awk '{print NR}' /etc/fstab ; awk END'{print NR}' /etc/fstab


    NR:行號

~]# awk {print NR}' /etc/fstab /etc/fatab

    FNR:個文件分別計數,行號

~]#awk {print FNR}' /etc/fstab /etc/fatab


    FILENAME:當前文件名

~]# awk '{print FILENAME}' /etc/fstab 
/etc/fstab
/etc/fstab


            ARGC:命令行參數的個數 

          ~

]# awk '{print ARGC}' /etc/fstab /etc/inittab 
 ~]# awk 'BEGIN{print ARGC}' /etc/fstab /etc/inittab


            ARGV:數組,保存的是命令行所給定的各參數 

~]# awk 'BEGIN{print ARGV[0]}' /etc/fstab /etc/inittab
awk
 ~]# awk 'BEGIN{print ARGV[1]}' /etc/fstab /etc/inittab
/etc/fstab
 ~]# awk 'BEGIN{print ARGV[2]}' /etc/fstab /etc/inittab
/etc/inittab
~]# awk 'BEGIN{print ARGV[3]}' /etc/fstab /etc/inittab #沒有索引爲空


2.2    自定義變量

    選項位置定義:-v var=hello

    在program中定義:awk ‘BEGIN{test=”hello”;print test}’

示例:

[root@centos7 ~]# awk -v test='hello gawk' '{print test}' /etc/fstab
hello gawk
hello gawk
hello gawk

root@centos7 ~]# awk -v test='hello gawk' 'BEGIN{print test}' /etc/fstab
hello gawk

[root@centos7 ~]# awk 'BEGIN{r=test="hello,gawk";print test}' /etc/fstab
hello,gawk

[root@centos7 ~]# awk -F: '{sex="male";print $1,sex,age;age=18}' /etc/passwd
root male
bin male 18
daemon male 18

[root@centos7 ~]# cat awk.txt #腳本實現awk輸出
{print script,$1,$2}
[root@centos7 ~]# awk -F: -f awk.txt txt="awk" /etc/passwd   #-f調用swk腳本
 root x
 bin x

3、   printf命令

格式化輸出:printf “FORMAT”, item1, item2, ...

    

(1) 必須指定FORMAT 

(2) 不會自動換行,需要顯式給出換行控制符,\n 

(3) FORMAT中需要分別爲後面每個item指定格式符 


    print不需要指定,printf需要指定format

    printf後面的字串需要使用雙引號

    字串定義後的內容需要使用”,”分隔,後面直接跟Item1,item2….

    format用於指定後面的每個item的輸出格式

    printf語句不會自動打印換行符\n

格式符

    %s: 顯示字符串

    %d,%i: 顯示十進制整數

    %e,%E: 科學計數法數值顯示

    %f: 顯示爲浮點數

    %g,%G: 以科學數法或浮點形式顯示數值

    %c: 顯示字符的ASCII碼

    %u: 無符號整數

    %%: 顯示%號自身,相當於轉義

修飾符

    N: 顯示寬度

    -: 左對齊(默認爲右對齊)

    +: 顯示數值符號


示例:


[root@centos7 ~]# awk -F: '{printf"%s",$1}' /etc/passwd
rootbindaemonadmlpsyncshutdownhaltmailoperatorgamesftpnobodysystemd-networkdbuspolkitdabrtlibstoragemgmtrpccolordsaslauthrtkitchronyqemutssusbmuxdgeocluerpcusernfsnobodyradvdsetroubleshootpulsegdmgnome-initial-s

[root@centos7 ~]# awk -F: '{printf"%s\n",$1}' /etc/passwd
root
bin
daemon
adm
lp
sync
shutdown
halt
mail
operator

[root@centos7 ~]# awk -F: '{printf"%-20s %10d\n",$1,$3}' /etc/passwd
root                          0
bin                           1
daemon                        2
adm                           3
lp                            4


[root@centos7 ~]# awk -F: '{printf"%-20.2s %10d\n",$1,$3}' /etc/passwd
ro 0
bi 1
da 2

[root@centos7 ~]# awk -F: '{print "username:%s\n",$1}' /etc/passwd
username:%s
 root
username:%s
 bin
 
 [root@centos7 ~]# awk -F: '{printf "username:%s,UID:%d\n",$1,$3}' /etc/passwd
username:root,UID:0
username:bin,UID:1
username:daemon,UID:2
username:adm,UID:3
username:lp,UID:4
username:sync,UID:5

[root@centos7 ~]# awk -F: '{printf "username:%15s,UID:%d\n",$1,$3}' /etc/passwd
username:           root,UID:0
username:            bin,UID:1
username:         daemon,UID:2          #%15s 右對齊
username:            adm,UID:3

[root@centos7 ~]# awk -F: '{printf "username:%-15s,UID:%d\n",$1,$3}' /etc/passwd
username:root           ,UID:0
username:bin            ,UID:1
username:daemon         ,UID:2          #%-15s 左對齊
username:adm            ,UID:3

[root@centos7 ~]#  awk -F: '{printf "username:%-20s salary:%-10.2f shell:%s\n",$1,$3,$7}' /etc/passwd
username:root                 salary:0.00       shell:/bin/bash
username:bin                  salary:1.00       shell:/sbin/nologin
username:daemon               salary:2.00       shell:/sbin/nologin
username:adm                  salary:3.00       shell:/sbin/nologin
username:lp                   salary:4.00       shell:/sbin/nologin
username:sync                 salary:5.00       shell:/bin/sync
username:shutdown             salary:6.00       shell:/sbin/shutdown
username:halt                 salary:7.00       shell:/sbin/halt



4、操作符

    算數操作符

    x+y, x-y, x*y, x/y, x^y, x%y

    -x: 轉換爲負數 +x: 轉換爲數值 

    字符串操作符:沒有符號的操作符,字符串連接 

    賦值操作符

    =, +=, -=, *=, /=, %=, ^=,++, —

    比較操作符

    ==, !=, >, >=, <, <=

    模式匹配符

    ~:左邊是否和右邊匹配包含!~:是否不匹配


示例:

計算1加到100和爲多少[root@centos7 ~]# echo {1..100}|tr " " + |bc
5050

[root@centos7 ~]# for ((sum=0,i=1;i<=100;i++));do let sum+=i;done;echo $sum
5050

[root@centos7 ~]# awk BEGIN'{for(i=1;i<=100;i++){sum+=i};print sum}'
5050

[root@centos7 ~]# awk BEGIN'{i=1;while (i<=100) {sum+=i;i++};print sum}'
5050
計算1加到100奇偶數和
#100以內偶奇數相加之和
[root@centos6 ~]# awk BEGIN'{sum=0;for(i=1;i<=100;i++){if(i%2==0){continue};sum+=i};print sum}'
2500

#100以內偶數相加之和
[root@centos6 ~]# awk BEGIN'{sum=0;for(i=1;i<=100;i++){if(i%2==1){continue};sum+=i};print sum}'
2550
#列出十以內的奇數
[root@centos6 ~]# seq 10 |awk '{if($1%2==0){next};print $1}'
1
3
5
7
9
#列出十以內的偶數
[root@centos6 ~]# seq 10 |awk '{if($1%2!=0){next};print $1}'
2
4
6
8
10

[root@centos7 ~]# awk -F: '$0 ~ /root/' /etc/passwd
root:x:0:0:root:/root:/bin/bash
operator:x:11:0:operator:/root:/sbin/nologin

root@centos7 ~]# awk -F: '$0 ~ /root/{print $1}' /etc/passwd
root
operator

[root@centos7 ~]# awk -F: '$0 ~ /^root/' /etc/passwd
root:x:0:0:root:/root:/bin/bash

[root@centos7 ~]# awk -F: '$0 !~ /root/' /etc/passwd
bin:x:1:1:bin:/bin:/sbin/nologin
daemon:x:2:2:daemon:/sbin:/sbin/nologin
adm:x:3:4:adm:/var/adm:/sbin/nologin
lp:x:4:7:lp:/var/spool/lpd:/sbin/nologin
.......

[root@centos7 ~]# awk -F: '$3==0' /etc/passwd
root:x:0:0:root:/root:/bin/bash

性能比較

[root@centos7 ~]# time(seq –s ”+” 1000000|bc)  #bc運算 
seq: invalid floating point argument: –s
Try 'seq --help' for more information.
real	0m0.004s
user	0m0.000s
sys	0m0.003s
[root@centos7 ~]# time(for ((i=0;i<=1000000;i++));do let total+=i;done;echo $total) #shell for運算
500000500000
real	0m7.236s
user	0m6.990s
sys	0m0.231s
[root@centos7 ~]#
[root@centos7 ~]# time(total=0;for i in {1..1000000};do total=$(($total+i));done;echo $total) #bash for運算
500000500000
real	0m7.150s
user	0m4.949s
sys	0m0.878s

[root@centos7 ~]# time (awk 'BEGIN{ total=0;for(i=0;i<=1000000;i++){total+=i;};print total;}') #awk運算
500000500000
real	0m0.217s
user	0m0.092s
sys	0m0.002s

邏輯操作符

    與&&,或||,非! : 

示例:

[root@centos7 ~]# awk -F: '$3>=0 && $3<=1000 {print $1}' /etc/passwd
root
bin
daemon

[root@centos7 ~]# awk -F: '$3==0 || $3<=1000 {print $1}' /etc/passwd
root
bin
daemon

[root@centos7 ~]# awk -F: '!($3==0) {print $1}' /etc/passwd
bin
daemon
adm

[root@centos7 ~]# awk -F: '($3>=1000) {print $3}' /etc/passwd
65534
1000
1001
1002
4444

[root@centos7 ~]# awk -F: '!($3>=1000) {print $1}' /etc/passwd
root
bin
daemon
adm

[root@centos7 ~]# awk -F: '$3>=1000{print $1,$3}' /etc/passwd
nfsnobody 65534
li 1000
123 1001
12 1002
19 4444


函數調用: function_name(argu1, argu2, ...) 

條件表達式(三目表達式):

        selector?if-true-expression:if-false-expression


示例: 

[

[root@centos7 ~]# awk -F: '{$3>=1000?UserType="Common User":UserType="Sysasmin or sysUser";printf "%15s: %s\n",$1,UserType}' /etc/passwd
           root: Sysasmin or sysUser
            bin: Sysasmin or sysUser
         daemon: Sysasmin or sysUser
            adm: Sysasmin or sysUser
             lp: Sysasmin or sysUser
           sync: Sysasmin or sysUser
       shutdown: Sysasmin or sysUser
           halt: Sysasmin or sysUser
           mail: Sysasmin or sysUser
       operator: Sysasmin or sysUser
          games: Sysasmin or sysUser
            ftp: Sysasmin or sysUser
         nobody: Sysasmin or sysUser
systemd-network: Sysasmin or sysUser
           dbus: Sysasmin or sysUser
        polkitd: Sysasmin or sysUser
           abrt: Sysasmin or sysUser
 libstoragemgmt: Sysasmin or sysUser
            rpc: Sysasmin or sysUser
         colord: Sysasmin or sysUser
       saslauth: Sysasmin or sysUser
          rtkit: Sysasmin or sysUser
         chrony: Sysasmin or sysUser
           qemu: Sysasmin or sysUser
            tss: Sysasmin or sysUser
        usbmuxd: Sysasmin or sysUser
        geoclue: Sysasmin or sysUser
        rpcuser: Sysasmin or sysUser
      nfsnobody: Common User
          radvd: Sysasmin or sysUser
 setroubleshoot: Sysasmin or sysUser
          pulse: Sysasmin or sysUser
            gdm: Sysasmin or sysUser
gnome-initial-setup: Sysasmin or sysUser
           sshd: Sysasmin or sysUser
          avahi: Sysasmin or sysUser
        postfix: Sysasmin or sysUser
            ntp: Sysasmin or sysUser
        tcpdump: Sysasmin or sysUser
             li: Common User
         apache: Sysasmin or sysUser
            123: Common User
             12: Common User
             19: Common User

5、PATTERN

         PATTERN:根據pattern條件,過濾匹配的行,再做處理 

(1)如果未指定:空模式,匹配每一行 

(2) /regular expression/:僅處理能夠模式匹配到的行,需要用/  /括起來 

awk '/^UUID/{print $1}' /etc/fstab  僅處理匹配到的行

awk '!/^UUID/{print $1}' /etc/fstab 僅處理匹配到的行

(3) relational expression: 關係表達式,結果有“真”有“假”;結果爲“真”纔會被處理 ;

真:結果爲非0值,非空字符串 

假:結果爲空字符串或0值 

(4) line ranges:行範圍

                startline,endline:/pat1/,/pat2/    處理 pattern1 到 pattern2 之間

                注意:不支持直接給出數字格式 


(5) BEGIN/END模式 

BEGIN{}: 僅在開始處理文件中的文本之前執行一次

 END{}:僅在文本處理完成之後執行一次

示例:

[root@centos7 ~]# df #處理前顯示
Filesystem     1K-blocks    Used Available Use% Mounted on
/dev/sda2       20961280 3750180  17211100  18% /
devtmpfs          485144       0    485144   0% /dev
tmpfs             499848       0    499848   0% /dev/shm
tmpfs             499848   19832    480016   4% /run
tmpfs             499848       0    499848   0% /sys/fs/cgroup
/dev/sda5       20961280   32948  20928332   1% /app
/dev/sda1         201380  138984     62396  70% /boot
tmpfs              99972      36     99936   1% /run/user/0
/dev/sr0         8490330 8490330         0 100% /media

[root@centos7 ~]# df |grep /dev/sd |awk '{printf "DevName:%s Used:%s\n",$1,$5}'
#顯示/dev/sd開頭的行並對其輸出顯示進行優化
DevName:/dev/sda2 Used:18%
DevName:/dev/sda5 Used:1%
DevName:/dev/sda1 Used:70%

[root@centos7 ~]# df | awk '$0 ~ "/dev/sd" {printf "DevName:%-10s Used:%s\n",$1,$5}'
DevName:/dev/sda2  Used:18%
DevName:/dev/sda5  Used:1%
DevName:/dev/sda1  Used:70%

[root@centos7 ~]#  df |awk '$1~"^/dev/sd[[:lower:]][[:digit:]]\\>" && $5>=10 {printf "Filesystem: %-15s Used: %s\n",$1,$5}'
Filesystem: /dev/sda2       Used: 18%
Filesystem: /dev/sda1       Used: 70%

[root@centos7 ~]# df |awk '/\/dev\/sd[[:lower:]][[:digit:]]\>/{if($5>10){printf "DevName:%-10s Used:%s\n",$1,$5}}'
DevName:/dev/sda2  Used:18%
DevName:/dev/sda1  Used:70%

[root@centos7 ~]# awk -F: '$3<1000{print $1,$3 }' /etc/passwd
root 0
bin 1
daemon 2
adm 3
lp 4
sync 5
shutdown 6
halt 7
mail 8
operator 11
games 12
ftp 14
nobody 99
systemd-network 192
dbus 81
polkitd 999
abrt 173
libstoragemgmt 998
rpc 32
colord 997
saslauth 996
rtkit 172
chrony 995
qemu 107
tss 59
usbmuxd 113
geoclue 994
rpcuser 29
radvd 75
setroubleshoot 993
pulse 171
gdm 42
gnome-initial-setup 992
sshd 74
avahi 70
postfix 89
ntp 38
tcpdump 72
apache 48

[root@centos7 ~]# awk -F: '$NF=="/bin/bash"{print $1,NF }' /etc/passwd  
#匹配最後一列爲"/bin/bash",輸出$1和列數NF的值
root 7
li 7
123 7
12 7
19 7

[root@centos7 ~]# awk -F: '$NF=="/bin/bash"{print $1,$NF }' /etc/passwd
#匹配最後一列爲"/bin/bash",輸出$1和$NF變量的值
root /bin/bash
li /bin/bash
123 /bin/bash
12 /bin/bash
19 /bin/bash

[root@centos7 ~]# awk -F: '$NF ~ "/bin/bash"{print $1,$NF }' /etc/passwd #
root /bin/bash
li /bin/bash
123 /bin/bash
12 /bin/bash
19 /bin/bash

[root@centos7 ~]# awk -F: '$NF ~ /bash$/{print $1,$NF }' /etc/passwd
root /bin/bash
li /bin/bash
123 /bin/bash
12 /bin/bash
19 /bin/bashm


[root@centos7 ~]# awk -F: '(NR<=28&&NR>=10){print $1}' /etc/passwd
operator
games
ftp
nobody
systemd-network
dbus
polkitd
abrt
libstoragemgmt
rpc
colord
saslauth
rtkit
chrony
qemu
tss
usbmuxd
geoclue
rpcuser


[root@centos7 ~]# awk '/UUID/{print $1}' /etc/fstab
UUID=24d11781-1f0f-4fe5-805c-6ca807fd24ff
UUID=0cd9ec5d-a77e-46f4-b218-19d914a5ed1e
UUID=3535b5f0-7b38-4cc9-a099-551fa388392c
UUID=c424d9be-be2c-4e7c-a007-1af750d9310b

[root@centos7 ~]# awk -F: '/^root\>/,/^ftp\>/{print $1}' /etc/passwd #root開頭到ftp開頭之間的行 
root
bin
daemon
adm
lp
sync
shutdown
halt
mail
operator
games
ftp

[root@centos7 ~]# awk -F: 'BEGIN{print "                USER   USERID"}/^root\>/,/^ftp\>/{printf "%20s %s %-5s\n", $1,":",$3}END{print "                 end   file"}' /etc/passwd    
#BEGIN指定(修飾)第一個輸出,/^root\>/,/^ftp\>指定(修飾)範圍第二個輸出,END指定(修飾)最後一個輸出範圍
                USER   USERID
                root : 0    
                 bin : 1    
              daemon : 2    
                 adm : 3    
                  lp : 4    
                sync : 5    
            shutdown : 6    
                halt : 7    
                mail : 8    
            operator : 11   
               games : 12   
                 ftp : 14   
                 end   file

                 
                 [root@centos7 ~]# awk -F: 'BEGIN{print "user uid \n------------------"}/^root\>/,/^ftp\>/{print $1,$3}' /etc/passwd
user uid
------------------
root 0
bin 1
daemon 2
adm 3
lp 4
sync 5
shutdown 6
halt 7
mail 8
operator 11
games 12
ftp 14

[root@centos7 ~]# awk -F: 'BEGIN{print "user uid \n------------------"}/^root\>/,/^ftp\>/{print $1,$3}END{print "==============="}' /etc/passwd
user uid
------------------
root 0
bin 1
daemon 2
adm 3
lp 4
sync 5
shutdown 6
halt 7
mail 8
operator 11
games 12
ftp 14
===============


6、常用的action

(1) Expressions:算術,比較表達式等 

(2) Control statements:if, while等

(3) Compound statements:組合語句

(4) input statements 

(5) output statements:print等



7控制語句


簡述控制語句格式:

if(condition){statments}

if(condition){statments} else {statments}

while(condition){statments}

do {statements} while (condition)

for(expr1;expr2;expr3){statements}

break

continue

delete array [index]

delete array 

exit

{statements}


7.1    if-else

語法:

if(condition){statments}

if(condition){statments} else {statments}

if(condition1){statement1}else if(condition2){statement2} else{statement3} 

使用場景:對awk取得的整行或某個字段做條件判斷 


示例:


[root@centos7 ~]# awk 'BEGIN{ test=100;if(test>90){print "very good"}else if(test>60){ print "good"}else{print "no pass"}}'
very good

成績爲100;大於90打印“very good”;大於60打印“good”;其餘打印“no pass”
[root@centos7 ~]# awk '{if($3>=1000){printf "Common user: %s\n",$1 } else{printf "root or sysuser : %s\n",$1}}' /etc/passwd
root or sysuser : root:x:0:0:root:/root:/bin/bash
root or sysuser : bin:x:1:1:bin:/bin:/sbin/nologin
root or sysuser : daemon:x:2:2:daemon:/sbin:/sbin/nologin
root or sysuser : adm:x:3:4:adm:/var/adm:/sbin/nologin
root or sysuser : lp:x:4:7:lp:/var/spool/lpd:/sbin/nologin
root or sysuser : sync:x:5:0:sync:/sbin:/bin/sync
root or sysuser : shutdown:x:6:0:shutdown:/sbin:/sbin/shutdown
root or sysuser : halt:x:7:0:halt:/sbin:/sbin/halt
root or sysuser : mail:x:8:12:mail:/var/spool/mail:/sbin/nologin
root or sysuser : operator:x:11:0:operator:/root:/sbin/nologin
root or sysuser : games:x:12:100:games:/usr/games:/sbin/nologin

[root@centos7 ~]# awk -F: '{if($NF=="/bin/bash")print $1}' /etc/passwd
#NF字段數量,$NF表示最後字段的值,判斷字段值等於/bin/bash
root
li
123
12
19

[root@centos7 ~]# awk '{if(NF>5)print $0}' /etc/passwd
#NF字段數量,判斷字段數大於5的行
tss:x:59:59:Account used by the trousers package to sandbox the tcsd daemon:/dev/null:/sbin/nologin
[root@centos7 ~]# awk '{if(NF>5)print $0}' /etc/fstab
# Created by anaconda on Tue Jan 9 05:14:54 2018
# Accessible filesystems, by reference, are maintained under '/dev/disk'
# See man pages fstab(5), findfs(8), mount(8) and/or blkid(8) for more info
UUID=24d11781-1f0f-4fe5-805c-6ca807fd24ff / xfs defaults 0 0
UUID=0cd9ec5d-a77e-46f4-b218-19d914a5ed1e /app xfs defaults 0 0
UUID=3535b5f0-7b38-4cc9-a099-551fa388392c /boot xfs defaults 0 0
UUID=c424d9be-be2c-4e7c-a007-1af750d9310b swap swap defaults 0 0
[root@centos7 ~]# df -h |awk -F% '{print $1}'
Filesystem Size Used Avail Use
/dev/sda2 20G 3.6G 17G 18
devtmpfs 474M 0 474M 0
tmpfs 489M 0 489M 0
tmpfs 489M 20M 469M 4
tmpfs 489M 0 489M 0
/dev/sda5 20G 33M 20G 1
/dev/sda1 197M 136M 61M 70
tmpfs 98M 36K 98M 1
/dev/sr0 8.1G 8.1G 0 100

[root@centos7 ~]# df -h |awk -F% '{print $1}'|awk '{print $NF}'
Use
18
0
0
4
0
1
70
1
100

[root@centos7 ~]# df -h |awk -F% '/^\/dev/{print $1}'|awk '{print $NF}'
18
1
70
100

#將/etc/passwd第一列當作姓名,第三列當作工資,打印報表,要求顯示:
#Name:zhangsan Salary:3300 Level:High
#工資大於3000的,Level顯示High,大於1000,小於等於3000的顯示Soso,小於1000的顯示LOW。 
[root@centos7 ~]#  awk -F: '{if($3>3000){Level="High"}else if($3>1000 && $3<=3000){Level="Soso"}else{Level="Low"};printf "Name:%-20s Salary:%-20d Level:%s\n",$1,$3,Level}' /etc/passwd
Name:root                 Salary:0                    Level:Low
Name:bin                  Salary:1                    Level:Low
Name:daemon               Salary:2                    Level:Low
Name:adm                  Salary:3                    Level:Low
Name:lp                   Salary:4                    Level:Low
Name:sync                 Salary:5                    Level:Low
Name:shutdown             Salary:6                    Level:Low
Name:halt                 Salary:7                    Level:Low
Name:mail                 Salary:8                    Level:Low
Name:operator             Salary:11                   Level:Low
Name:games                Salary:12                   Level:Low
Name:ftp                  Salary:14                   Level:Low
Name:nobody               Salary:99                   Level:Low
Name:systemd-network      Salary:192                  Level:Low
Name:dbus                 Salary:81                   Level:Low
Name:polkitd              Salary:999                  Level:Low
Name:abrt                 Salary:173                  Level:Low
Name:libstoragemgmt       Salary:998                  Level:Low
Name:rpc                  Salary:32                   Level:Low
Name:colord               Salary:997                  Level:Low
Name:saslauth             Salary:996                  Level:Low
Name:rtkit                Salary:172                  Level:Low
Name:chrony               Salary:995                  Level:Low
Name:qemu                 Salary:107                  Level:Low
Name:tss                  Salary:59                   Level:Low
Name:usbmuxd              Salary:113                  Level:Low
Name:geoclue              Salary:994                  Level:Low
Name:rpcuser              Salary:29                   Level:Low
Name:nfsnobody            Salary:65534                Level:High
Name:radvd                Salary:75                   Level:Low
Name:setroubleshoot       Salary:993                  Level:Low
Name:pulse                Salary:171                  Level:Low
Name:gdm                  Salary:42                   Level:Low
Name:gnome-initial-setup  Salary:992                  Level:Low
Name:sshd                 Salary:74                   Level:Low
Name:avahi                Salary:70                   Level:Low
Name:postfix              Salary:89                   Level:Low
Name:ntp                  Salary:38                   Level:Low
Name:tcpdump              Salary:72                   Level:Low
Name:li                   Salary:1000                 Level:Low
Name:apache               Salary:48                   Level:Low
Name:123                  Salary:1001                 Level:Soso
Name:12                   Salary:1002                 Level:Soso
Name:19                   Salary:4444                 Level:High

7.2    while循環

語法:while(condition){statments}

意義:條件”真”,進入循環;條件”假”,退出循環

        

使用場景:對於行內的多個字段逐一類似處理時使用,對數組中的個元素逐一處理時使用。


[root@centos7 ~]# awk '/^[[:space:]]*linux16/{i=1;while(i<=NF){print $1,length($i);i++}}' /etc/grub2.cfg
linux16 7
linux16 30
linux16 46
linux16 2
linux16 4
linux16 5
linux16 16
linux16 7
linux16 50
linux16 46
linux16 2
linux16 4
linux16 5

[root@centos7 ~]# awk '/^[[:space:]]*linux16/{i=1;while(i<=NF){if(length($i)>=40){print $1,length($i)};i++}}' /etc/grub2.cfg
#以空白符開頭後跟”linux16″的行中,把字符數大於40的字符串打印出來。
linux16 46
linux16 50
linux16 46


7.3    do-while循環

語法:do {statements} while (condition)

    (無論真假,至少執行一次循環體 )


示例:

[root@centos7 ~]# seq 3|awk 'BEGIN{i=1;print i++,i}'
#i的值:先輸出i的值,在做(加法)運算
1 2
[root@centos7 ~]# seq 3|awk 'BEGIN{i=1;print ++i,i}'
#i的值:先做(加法)運算,在輸出i 的值
2 2


[root@centos7 ~]# awk 'BEGIN{ total=0;i=0;do{ total+=i;i++;}while(i<=100);print total}'
#累加運算:計算0-100之和
5050

7.4    for循環

語法:for(expr1;expr2;expr3) {statement;…} 

常見用法:for(variable assignment;condition;iteration process) {for-body} 

特殊用法:

            能夠遍歷數組中的元素 

                        語法:for(var in array) {for-body}

示例:

[root@centos7 ~]#  awk '/^[[:space:]]*linux16/{for(i=1;i<=NF;i++) {print$i,length($i)}}' /etc/grub2.cfg
#遍歷:統計以linux16開頭的行各字符串出現次數
linux16 7
/vmlinuz-3.10.0-693.el7.x86_64 30
root=UUID=24d11781-1f0f-4fe5-805c-6ca807fd24ff 46
ro 2
rhgb 4
quiet 5
LANG=en_US.UTF-8 16
linux16 7
/vmlinuz-0-rescue-ff4aa58d9e1f44f7b7aae5f6fd1a3242 50
root=UUID=24d11781-1f0f-4fe5-805c-6ca807fd24ff 46
ro 2
rhgb 4
quiet 5


7.5    switch語句

語法:switch(expression) {case VALUE1 or /REGEXP/: statement1; case VALUE2 or /REGEXP2/: statement2; ...; default: statementn}


7.6    break和continue

break [n] 

continue [n]


awk ‘BEGIN{sum=0;for(i=1;i<=100;i++){if(i%2==0)continue;sum+=i}print sum}’
awk ‘BEGIN{sum=0;for(i=1;i<=100;i++){if(i==66)break;sum+=i}print sum}’

7.7    net

提前結束對本行處理而直接進入下一行處理(awk自身循環) 


示例:

[root@centos7 ~]# awk -F: '{if($3%2!=0)  print $1,$3}' /etc/passwd
root 0
daemon 2
lp 4
shutdown 6
mail 8
games 12
ftp 14
systemd-network 192
libstoragemgmt 998
rpc 32
saslauth 996
rtkit 172
geoclue 994
nfsnobody 65534
gdm 42
gnome-initial-setup 992
sshd 74
avahi 70
ntp 38
tcpdump 72
li 1000
apache 48
12 1002
[root@centos7 ~]# seq 20 | awk -F: '{if($1%2==0)next ; print $1}'
#打印奇數行;匹配$1%2取餘數的等於0的結束循環
1
3
5
7
9
11
13
15
17
19


8、array(數組 )

關聯數組:array[index-expression]

index-expression:

(1) 可使用任意字符串;字符串要使用雙引號括起來 

(2) 如果某數組元素事先不存在,在引用時,awk會自動創建 此元素,並將其值初始化爲“空串” 

若要判斷數組中是否存在某元素,要使用“index in array”格 式進行遍歷 

若要遍歷數組中的每個元素,要使用for循環;

for(var in array) {for-body}

注意:var會遍歷array的每個索引;

state["LISTEN"]++

state["ESTABLISHED"]++

9、函數

數值處理:

rand():返回0和1之間一個隨機數

[root@centos7 ~]# awk 'BEGIN{srand();print int(rand()*100)}'
#隨機一個兩位數的整數,*100
71

字符串處理:

length([s]):返回指定字符串的長度

sub(r,s,[t]):對t字符串進行搜索r表示的模式匹配的內容,並將第一個匹 配的內容替換爲s

[root@nanyibo ~]# echo "2018:3:30 17:38:30" |awk 'sub(/:/,"-",$1)'
2018-3:30 17:38:30

gsub(r,s,[t]):對t字符串進行搜索r表示的模式匹配的內容,並全部替換 爲s所表示的內容

[root@nanyibo ~]# echo "2018:3:30 17:38:30" |awk 'gsub(/:/,"-",$1)'
2018-3-30 17:38:30

split(s,array,[r]):以r爲分隔符,切割字符串s,並將切割後的結果保存 至array所表示的數組中,第一個索引值爲1,第二個索引值爲2,…

netstat -tan | awk '/^tcp\>/{split($5,ip,":");count[ip[1]]++} END{for (i in count) {print i,count[i]}}'
#先進行分割,取出第五列對第五列做分割取出以分隔符:的第一列,設置變量count索引爲ip[1]做加法運算,只輸出一次結果。

自定義函數

格式:

function name ( parameter, parameter,  ... ) { 
                       statements 
                       return expression 
                                      }

示例:

#cat fun.awk function max(
                v1,v2) { v1>v2?var=v1:var=v2
                 return var
     } 
BEGIN{a=3;b=2;print max(a,b)} 
#awk –f fun.awk


示例:


[root@nana ~]# cat  fi.txt
1 2 3 4 5 6 7 8 9 10
11 12 12 14 15 16 17 18 19 20
[root@nana ~]# awk '{i=1;sum=0;while(i<=NF){sum+=$i;i++};print sum}' f1.txt 顯示每行各自的總行
55
155
[root@nana ~]# awk '{i=1;while(i<=NF){sum+=$i;i++};print sum}' f1.txt 每行顯示一次總和
55
210
[root@nana ~]# awk '{i=1;while(i<=NF){sum+=$i;i++}}END{print sum}' f1.txt 只顯示總和
210


對十以內整數奇數輸出jishu,偶數輸出偶數

效果如下:

1 jishu

2 oushu

3 jishu

[root@centos7 /]# echo {1..10} |awk '{i=1;while(i<=NF){if($i%2==0){print $i,"is oushu"} else{print $i, "is jishu"};i++}}'
1 is jishu
2 is oushu
3 is jishu
4 is oushu
5 is jishu
6 is oushu
7 is jishu
8 is oushu
9 is jishu
10 is oushu


[root@centos7 ~]# awk 'BEGIN{weekdays["mon"]="Monday";weekdays["tue"]="Tuesday";for(i in weekdays) {print weekdays[i]}}'
Tuesday
Monday
[root@centos7 ~]# awk 'BEGIN{weekdays["mon"]="Monday";weekdays["tue"]="Tuesday";for(i in weekdays) {print weekdays[i] ,i}}'
#i的值爲每次數組weekdays的索引,這個過程稱爲遍歷
Tuesday tue
Monday mon

函數統計類型出現次數

~]# netstat -tan |awk '/^tcp\>/{state[$NF]++}END{for (i in state){ print i,state[i]}}'
#函數state中下標爲$NF的值:LISTEN和ESTABLISHED,他們的值做++運算,
#END{}:僅在文本完成之後執行一次,後邊for循環只做一次,
#i變量的值爲:數組state的下標,也就是:LISTEN和ESTABLISHED。
#print i的值爲for訓話i的值,就是$NF的值:LISTEN和ESTABLISHED。
#state[i]的值爲,END前邊完成時的值++的相加之和,
#也就是state數組的值:state[LISTEN]=3和state[ESTABLISHED]=1
LISTEN 8
ESTABLISHED 3

顯示/bash類型次數

[root@centos7 ~]# awk -F: '{shell[$7]++}END{for(n in shell){print n,shell[n]}}' /etc/passwd
/bin/sync 1
/bin/bash 5
/sbin/nologin 36
/sbin/halt 1
/sbin/shutdown 1

統計http日誌文件,IP地址訪問次數

[root@centos7 ~]# awk '{ip[$1]++}END{for(i in ip){print i ,ip[i]}}' /var/log/httpd/access_log

172.18.253.55 1788
172.18.251.122 52
172.18.251.150 34
172.18.251.141 30
172.18.251.160 157
172.18.251.170 457
172.18.251.107 14
172.18.251.109 51
172.18.251.145 50
172.18.0.223 12
172.18.253.21 74087
::1 15
172.18.251.147 354
172.18.254.78 183
172.18.251.157 330
172.18.252.134 514
172.18.251.149 158
172.18.254.6 1643
172.18.250.183 81
172.18.251.21 81
172.18.254.34 659

awk實現取出從定向

[root@centos7 ~]# awk -F: '! shell[$7]++' /etc/passwd
root:x:0:0:root:/root:/bin/bash
bin:x:1:1:bin:/bin:/sbin/nologin
sync:x:5:0:sync:/sbin:/bin/sync
shutdown:x:6:0:shutdown:/sbin:/sbin/shutdown
halt:x:7:0:halt:/sbin:/sbin/halt

去重

[root@centos6 ~]#awk -F: '!shell[$0]++' /etc/passwd #去重

統計/etc/fstab文件中每個文件系統類型出現的次數;

#源文件
[root@centos7 ~]# awk '/^UUID/{print $0}' /etc/fstab
UUID=24d11781-1f0f-4fe5-805c-6ca807fd24ff /                       xfs     defaults        0 0
UUID=0cd9ec5d-a77e-46f4-b218-19d914a5ed1e /app                    xfs     defaults        0 0
UUID=3535b5f0-7b38-4cc9-a099-551fa388392c /boot                   xfs     defaults        0 0
UUID=c424d9be-be2c-4e7c-a007-1af750d9310b swap                    swap    defaults        0 0

[root@centos7 ~]# awk '/^UUID/{fs[$3]++}END{for(i in fs) {print i,fs[i]}}' /etc/fstab
swap 1
xfs 3

統計指定文件中每個單詞出現的次數;

[root@centos7 ~]# awk '{for(i=1;i<=NF;i++){count[$i]++}}END{for(i in count) {print i,count[i]}}' /etc/fstab 
UUID=c424d9be-be2c-4e7c-a007-1af750d9310b 1
Tue 1
man 1
and/or 1
UUID=0cd9ec5d-a77e-46f4-b218-19d914a5ed1e 1
maintained 1
xfs 3
Accessible 1
# 7
are 1
defaults 4
Jan 1
blkid(8) 1
/ 1
0 8
See 1
Created 1
05:14:54 1
on 1
mount(8) 1
9 1
anaconda 1
UUID=3535b5f0-7b38-4cc9-a099-551fa388392c 1
fstab(5), 1
/app 1
/boot 1
findfs(8), 1
2018 1
'/dev/disk' 1
by 2
/etc/fstab 1
pages 1
more 1
info 1
swap 2
filesystems, 1
reference, 1
UUID=24d11781-1f0f-4fe5-805c-6ca807fd24ff 1
for 1
under 1

腳本實現AWK

system命令

空格是awk中的字符串連接符,如果system中需要使用awk中 的變量可以使用空格分隔,或者說除了awk的變量外其他一律 用""引用起來。

awk BEGIN'{system("hostname") }' awk 'BEGIN{score=100; system("echo  your score is " score) }'

[root@nanyibo ~]# cat awk.txt
function max(v1,v2){
        v1>v2?var=v1:var=v2
        return var
}
BEGIN{print max(a,b)}
[root@nanyibo ~]# awk -v a=30 -v b=20 -f awk.txt
30
[root@nanyibo ~]# awk -v a=10 -v b=20 -f awk.txt
20

 將awk程序寫成腳本,直接調用或執行

示例:

#cat f1.awk 
            {if($3>=1000)print $1,$3} 
#awk -F: -f f1.awk /etc/passwd
#cat f2.awk 
        #!/bin/awk –f 
        #this is a awk script 
        {if($3>=1000)print $1,$3} 
#chmod +x f2.awk 
#f2.awk –F:  /etc/passwd


向awk腳本傳遞參

格式:

         awkfile  var=value var2=value2... Inputfile

注意:在BEGIN過程中不可用。直到首行輸入完成以後,變 量纔可用。可以通過-v 參數,讓awk在執行BEGIN之前得到 變量的值。命令行中每一個指定的變量都需要一個-v參數

示例:

#cat  test.awk   
        #!/bin/awk –f 
        {if($3 >=min && $3<=max)print $1,$3} 
#chmod +x test.awk 
#test.awk -F: min=100 max=200  /etc/passwd






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