天天看點

shell程式設計----awk

目錄标題

      • 1. awk
      • 2. awk模式比對
      • 3. 記錄和域
      • 4. 關系和布爾運算符
      • 5. 表達式
      • 6. 系統變量
      • 7. 格式輸出
      • 8. 内置函數
      • 練習

1. awk

  正規表達式的擴充,awk、perl等支援正規表達式擴充出來的一些元字元。

擴充的正規表達式元字元及其意義

符号 意義
比對0個或1個在其之前的那個普通字元
+ 比對1個或多個在其之前的那個普通字元
() 表示一個字元集合或用在expr中
| 表示“或”,比對一組可選的字元
  1. “?”

      比對之前那個字元0次或1次

      如:jo?b,該表達式表示比對o字元0次或1次,即比對job或joob。“?”至多可以比對1個字元。

  2. “+”

      與“”類似,都是比對其前面的那個字元多次,但是“”符号可以比對0次,而“+”符号至少比對1次。

      如:s+eu表示比對s1次或任意次,sseu,ssseu等字元串都可由該表達式進行比對,而seu卻不能由s+eu來比對。

  3. “()”字元和”字元

      “()”符号通常與“|”符号結合使用,表示一組可選字元的集合,如:

    re(a|b|c)d 該表達式中(a|b|c)表示在字元a、b、c中選擇任意一個字元,即read、rebd、recd都是由該表達式進行比對。

      事實上,“()”符号很少被使用到,因為“[]”符号完全能夠代替“()”符号表示一組可選字元的集合,re(a|b|c)d就等價于re[a|b|c]d

      “|”符号也可以表示多個正規表達式的“或”關系,基本格式為:re1|re2|re3|… 1其中re1,re2和re3表示正規表達式。

  通過awk可以建立程式,這些程式讀取輸入檔案、為資料排序、處理資料、對輸入執行計算以及生成報表,還有無數其它的功能。awk适合文本處理和報表生成,其文法較為常見,借鑒了某些語言的精華,如c語言等。在linux系統日常處理工作中,發揮着很重要的作用,掌握了awk将會使你的工作量變得高大上。

  awk程式由一個主輸入循環維持,主輸入循環反複執行,直到條件被觸發,主輸入循環無須由程式員取寫,awk已經搭好主輸入循環的架構。

2. awk模式比對

  任何awk語句都有模式(pattern)和動作(action)組成模式是由一組用于測試輸入行是否需要執行動作的規則。動作包含語句,函數和表達式的執行過程,簡言之,模式決定動作和時觸發和觸發時間動作執行對輸入行的處理。

[[email protected] awk]# sed '=' test1 
1

2

3

4

[[email protected] awk]# awk '/^$/{printf "This is a blank line.\n"}' test1 
This is a blank line.
This is a blank line.
This is a blank line.
This is a blank line.
           

将操作寫入檔案中

[[email protected] awk]# awk -f test1.awk test1
This is a blank line.
This is a blank line.
This is a blank line.
This is a blank line.
[[email protected] awk]# cat test1.awk 
/^$/{printf "This is a blank line.\n"}
           

直接執行

[[email protected] awk]# ./test1.awk test1
This is a blank line.
This is a blank line.
This is a blank line.
This is a blank line.
[[email protected] awk]# cat test1.awk 
#!/usr/bin/awk -f
/^$/{printf "This is a blank line.\n"}
           

3. 記錄和域

  awk認為輸入檔案是結構化的,awk将每個輸入檔案行定義為記錄,行中的每個字元串定義為域,域之間用空格,Tab鍵或其它符号進行分隔,分隔域的符号就叫做分隔符。

  awk定義與操作符 來 指 定 執 行 動 作 的 域 , 域 操 作 符 來指定執行動作的域,域操作符 來指定執行動作的域,域操作符後面跟數字或變量來辨別域的位置,每條記錄的域從1開始編号,如$1表示第一個域,$0表示所有域。

$0表示所有域

[[email protected] awk]# awk '{print $0}' test2
jy	Zhang 8497335  shanxi
jy	Zhang 8497335  shanxi
jy	Zhang 8497335  shanxi
jy	Zhang 8497335  shanxi
jy	Zhang 8497335  shanxi
           

$2,$1,$3,$4

[[email protected] awk]# awk '{print $2,$1,$3,$4}' test2
Zhang jy 8497335 shanxi
Zhang jy 8497335 shanxi
Zhang jy 8497335 shanxi
Zhang jy 8497335 shanxi
Zhang jy 8497335 shanxi
           
[[email protected] awk]# awk 'BEGIN {one=1;two=2} {print $(one+two)}' test2
8497335
8497335
8497335
8497335
8497335
           

tab鍵被認為是連續的空格鍵來處理

[[email protected] awk]# cat test2
jy	Zhang 8497335  shanxi
jy	Zhang 8497335  shanxi
jy	Zhang 8497335  shanxi
jy	Zhang 8497335  shanxi
jy	Zhang 8497335  shanxi
jy Zhang 8497335  shanxi
jy Zhang 8497335  shanxi
jy Zhang 8497335  shanxi
[[email protected] awk]# awk 'BEGIN {one=1;two=2} {print $(one+two)}' test2
8497335
8497335
8497335
8497335
8497335
8497335
8497335
8497335
           

用tab鍵分隔域

[[email protected] awk]# cat test2
jy		Zhang 8497335  shanxi
jy		Zhang 8497335  shanxi
jy		Zhang 8497335  shanxi
jy		Zhang 8497335  shanxi
jy	Zhang 8497335  shanxi
[[email protected] awk]# awk -F "\t" '{print $1}' test2
jy
jy
jy
jy
jy
[[email protected] awk]# awk -F "\t" '{print $2}' test2




Zhang 8497335  shanxi
[[email protected] awk]# awk -F "\t" '{print $3}' test2  # \t:表示tab
Zhang 8497335  shanxi
Zhang 8497335  shanxi
Zhang 8497335  shanxi
Zhang 8497335  shanxi
           

注意:不要用多個tab

如果出現多個tab,使用如下指令解決

[[email protected] awk]# cat test2
jy			Zhang 8497335  shanxi
jy			Zhang 8497335  shanxi
jy			Zhang 8497335  shanxi
jy		Zhang 8497335  shanxi
jy	Zhang 8497335  shanxi
[[email protected] awk]# awk -F "\t+" '{print $2}' test2
Zhang 8497335  shanxi
Zhang 8497335  shanxi
Zhang 8497335  shanxi
Zhang 8497335  shanxi
Zhang 8497335  shanxi


[[email protected] awk]# awk 'BEGIN {FS=","} {print $1,$3}' test3
jy 8497335  shanxi
jy 8497335  shanxi
jy 8497335  shanxi
jy 8497335  shanxi
jy 8497335  shanxi
           

4. 關系和布爾運算符

  awk定義了一組關系運算符用于awk模式比對。

awk關系運算符及其意義

元算符 意義
< 小于
> 大于
<= 小于或等于
>= 大于或等于
== 等于
比對正規表達式
!~ 不比對正規表達式

$1比對第一個域為root的内容

[[email protected] awk]# awk 'BEGIN {FS=":"} $1~/root/' passwd 
root:x:0:0:root:/root:/bin/bash
           

所有的域不比對/root/

[[email protected] awk]# awk 'BEGIN {FS=":"} $0!~/root/' 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
sync:x:5:0:sync:/sbin:/bin/sync
           
[[email protected] awk]# awk 'BEGIN {FS=":"} {if ($3<$4) print$0}' passwd 
adm:x:3:4:adm:/var/adm:/sbin/nologin
lp:x:4:7:lp:/var/spool/lpd:/sbin/nologin
mail:x:8:12:mail:/var/spool/mail:/sbin/nologin
games:x:12:100:games:/usr/games:/sbin/nologin
ftp:x:14:50:FTP User:/var/ftp:/sbin/nologin
           

||表示或 ==是精确比對

[[email protected] awk]# awk 'BEGIN {FS=":"} {if ($3==1||$4==7) print$0}' passwd 
bin:x:1:1:bin:/bin:/sbin/nologin
lp:x:4:7:lp:/var/spool/lpd:/sbin/nologin
           

5. 表達式

  與其它程式設計一樣,awk表達式用于存儲,操作和擷取資料。一個awk表達式可由數值,字元常量,變量,操作符,函數和正規表達式自由組合而成。

  變量是一個值的辨別符,定義awk變量非常友善,隻需要定義一個變量名并将值賦給它們即可。

  變量名隻是包含字母,數字和下劃線而且不能以數字開通。

  定義awk變量無須生命變量類型,每個變量由兩種類型的值:字元串值和數值。

  awk根據表達式上下文來确定使用哪個值。變量的預設值為0,預設字元串值為空。

統計空白數

[[email protected] awk]# awk '/^$/{print x++}' test1
0
1
2
3
[[email protected] awk]# awk '/^$/{print ++x}' test1
1
2
3
4
           

平均值的計算

[[email protected] awk]# cat test4
jy,Zhang,8497335,77,88,99,100
jy,Zhang,8497335,25,45,15,65
jy,Zhang,8497335,99,55,26,29
jy,Zhang,8497335,77,19,48,53
jy,Zhang,8497335,93,88,84,72
[[email protected] awk]# cat test4.awk 
#!/usr/bin/awk -f
BEGIN {FS=","}
{total=$4+$5+$7
avg=total/4
print $1,avg
}
[[email protected] awk]# chmod o+x test4.awk 
[[email protected] awk]# ./test4.awk test4
jy 66.25
jy 33.75
jy 45.75
jy 37.25
jy 63.25
           

6. 系統變量

  awk定義了很多内建變量用于設定環境資訊,我們稱他為系統變量。

  這些系統變量可分為:第一種用于改變awk的預設值,如域分隔符。第二種用于定義系統值,在處理文本時可以讀取這些系統值如記錄中的域數量,目前記錄數,目前檔案名等。

  NF:為記錄的域數量

  NR:顯示目前的記錄數,該值根據讀取輸入檔案的進度而變化,讀取第一條記錄時,NR=1讀取到檔案末尾時,NR為該檔案包含的記錄數。

  $0表示列印記錄的所有域

  FILENAME:儲存了目前的輸入檔案名

[[email protected] awk]# awk 'BEGIN {FS=","} {print NF,NR,$0} END {print FILENAME}' test4
7 1 jy,Zhang,8497335,77,88,99,100
7 2 jy,Zhang,8497335,25,45,15,65
7 3 jy,Zhang,8497335,99,55,26,29
7 4 jy,Zhang,8497335,77,19,48,53
7 5 jy,Zhang,8497335,93,88,84,72
test4
           

7. 格式輸出

  前面的例子隻涉及awk如何輸入檔案進行處理,對于輸出的格式并未規定。而awk的一大主要功能時産生報表,報表就是要求按照一定的格式輸出,awk借鑒c語言的文法,定義了printf輸出,它可以規定輸出的格式。

[[email protected] awk]# awk 'BEGIN {FS=","} {printf("%s\t%d\n",$2,$7)}' test4
Zhang	100
Zhang	65
Zhang	29
Zhang	53
Zhang	72

[[email protected] awk]# awk 'BEGIN {printf("%c\n",65)}'
A

[[email protected] awk]# awk 'BEGIN {printf("%f\n",35)}'
35.000000
[[email protected] awk]# awk 'BEGIN {printf("%.3f\n",35)}'
35.000
           

-10s表示将$1控制在10位,并且時左對齊,如果字元串不足15位使用空格補齊

[[email protected] awk]# awk 'BEGIN {FS=","}{printf("%-10s\t%s\n",$1,$3)}' test4
jy        	8497335
jy        	8497335
jy        	8497335
jy        	8497335
jy        	8497335
           

8. 内置函數

  awk提供了強大的内置字元串函數,用于實作文本的字元串替換 查找以及分割等功能

  gsub函數執行字元串替換功能,它将第一個字元串替換位第二個字元串。

  index和length函數。indes傳回第二個字元串在第一個字元串出現的首位置length傳回字元串的長度。

[[email protected] awk]# awk 'BEGIN {FS=":";OFS=":"} gsub(/root/,"student",$1) {print $0}' passwd 
student:x:0:0:root:/root:/bin/bash

[[email protected] awk]# awk 'BEGIN {FS=":"} gsub(/root/,"student",$1) {print $0}' passwd 
student x 0 0 root /root /bin/bash

[[email protected] awk]# awk 'BEGIN {print index("zjylilhahahxixi","ha")}'
7

[[email protected] awk]# awk 'BEGIN {print length("zjylilhahahxixi")}'
15
           

練習

  1. 輸出本機的ip位址
hostname -I
           
  1. 輸出本機的根分區使用率
[[email protected] ~]# df -h| awk '/\/dev\/vda1/{print $5}'
68%

[[email protected] ~]# df -h | awk '{if ($6=="/") print$5}'
68%
           
  1. 以passwd檔案為例,輸出其中以bash結尾的完整記錄
[[email protected] awk]# awk '/bash$/{print$0}' passwd 
root:x:0:0:root:/root:/bin/bash
student:x:1000:1000:Student User:/home/student:/bin/bash
           
  1. 列出以ro開頭的使用者記錄
[[email protected] awk]# awk '/^ro/{print$0}' passwd 
root:x:0:0:root:/root:/bin/bash
           
  1. 輸出以a,b,c或着d開頭的使用者名,宿主目錄
[[email protected] awk]# awk 'BEGIN {FS=":"} /^(a|b|c|d)/{print $1,$6}' passwd 
bin /bin
daemon /sbin
adm /var/adm
dbus /
avahi /var/run/avahi-daemon
avahi-autoipd /var/lib/avahi-autoipd
chrony /var/lib/chrony
colord /var/lib/colord
abrt /etc/abrt
apache /usr/share/httpd
dhcpd /
           
  1. 輸出其中用名以a開頭,登陸shell以nologin結尾的使用者名,登陸shell
[[email protected] awk]# awk '/^a/&&/nologin$/' passwd 
adm:x:3:4:adm:/var/adm:/sbin/nologin
avahi:x:70:70:Avahi mDNS/DNS-SD Stack:/var/run/avahi-daemon:/sbin/nologin
avahi-autoipd:x:170:170:Avahi IPv4LL Stack:/var/lib/avahi-autoipd:/sbin/nologin
abrt:x:173:173::/etc/abrt:/sbin/nologin
apache:x:48:48:Apache:/usr/share/httpd:/sbin/nologin
           
  1. 輸出第三行的使用者記錄
[[email protected] awk]#  awk '{if (NR==3) print$0}' passwd 
daemon:x:2:2:daemon:/sbin:/sbin/nologin
           
  1. 輸出奇數(行号NR除以2餘數為1)行的使用者記錄
[[email protected] awk]#  awk '{if (NR%2!=0) print$0}' passwd 
root:x:0:0:root:/root:/bin/bash
daemon:x:2:2:daemon:/sbin:/sbin/nologin
lp:x:4:7:lp:/var/spool/lpd:/sbin/nologin
shutdown:x:6:0:shutdown:/sbin:/sbin/shutdown
mail:x:8:12:mail:/var/spool/mail:/sbin/nologin
games:x:12:100:games:/usr/games:/sbin/nologin
nobody:x:99:99:Nobody:/:/sbin/nologin
polkitd:x:999:998:User for polkitd:/:/sbin/nologin
avahi-autoipd:x:170:170:Avahi IPv4LL Stack:/var/lib/avahi-autoipd:/sbin/nologin
rpcuser:x:29:29:RPC Service User:/var/lib/nfs:/sbin/nologin
ovirtagent:x:175:175:RHEV-M Guest Agent:/usr/share/ovirt-guest-agent:/sbin/nologin
sshd:x:74:74:Privilege-separated SSH:/var/empty/sshd:/sbin/nologin
student:x:1000:1000:Student User:/home/student:/bin/bash
colord:x:997:995:User for colord:/var/lib/colord:/sbin/nologin
libstoragemgmt:x:996:994:daemon account for libstoragemgmt:/var/run/lsm:/sbin/nologin
qemu:x:107:107:qemu user:/:/sbin/nologin
ntp:x:38:38::/etc/ntp:/sbin/nologin
radvd:x:75:75:radvd user:/:/sbin/nologin
gdm:x:42:42::/var/lib/gdm:/sbin/nologin
tcpdump:x:72:72::/:/sbin/nologin
dhcpd:x:177:177:DHCP server:/:/sbin/nologin
           
  1. 輸出偶數(行号除以2餘數為0)行的使用者記錄
[[email protected] awk]#  awk '{if (NR%2==0) print$0}' passwd 
bin:x:1:1:bin:/bin:/sbin/nologin
adm:x:3:4:adm:/var/adm:/sbin/nologin
sync:x:5:0:sync:/sbin:/bin/sync
halt:x:7:0:halt:/sbin:/sbin/halt
operator:x:11:0:operator:/root:/sbin/nologin
ftp:x:14:50:FTP User:/var/ftp:/sbin/nologin
dbus:x:81:81:System message bus:/:/sbin/nologin
avahi:x:70:70:Avahi mDNS/DNS-SD Stack:/var/run/avahi-daemon:/sbin/nologin
rpc:x:32:32:Rpcbind Daemon:/var/lib/rpcbind:/sbin/nologin
nfsnobody:x:65534:65534:Anonymous NFS User:/var/lib/nfs:/sbin/nologin
postfix:x:89:89::/var/spool/postfix:/sbin/nologin
chrony:x:998:996::/var/lib/chrony:/sbin/nologin
usbmuxd:x:113:113:usbmuxd user:/:/sbin/nologin
abrt:x:173:173::/etc/abrt:/sbin/nologin
unbound:x:995:993:Unbound DNS resolver:/etc/unbound:/sbin/nologin
saslauth:x:994:76:"Saslauthd user":/run/saslauthd:/sbin/nologin
rtkit:x:172:172:RealtimeKit:/proc:/sbin/nologin
pulse:x:171:171:PulseAudio System Daemon:/var/run/pulse:/sbin/nologin
gnome-initial-setup:x:993:991::/run/gnome-initial-setup/:/sbin/nologin
apache:x:48:48:Apache:/usr/share/httpd:/sbin/nologin