shell腳本--awk的基本使用

awk、sed和grep號稱文本處理三劍客。

(1)awk的基本用法

a)awk默認使用空白(一個或者多個空格、一個或者多個\t,一個或者多個空格和\t的組合)作爲分隔符。

例如:文件testfile

[root@172-0-10-222 shell-test]# cat testfile 
ll 201907001 80 97 70
kk 201907002 90 97 90
hh 201907003 60 67 60
jj 201907004 59 57 58
aa 201907005 23 34 12

使用awk獲取文件內容的第一列,結果如下:

[root@172-0-10-222 shell-test]# cat testfile | awk '{print $1}'
ll
kk
hh
jj
aa

b)假如有多個空格和\t,文件如下:

[root@172-0-10-222 shell-test]# cat testfile 
ll 	201907001 80 97 70
kk 		201907002 90 97 90
hh 201907003 60 67 60
jj 201907004 59 57 58
aa 201907005 23 34 12

使用awk默認分割效果跟上面一樣:

[root@172-0-10-222 shell-test]# cat testfile | awk '{print $1}'
ll
kk
hh
jj
aa

c)awk還可以使用多個不同字符進行文本的分割,文件如下:

[root@172-0-10-222 shell-test]# cat testfile 
ll:  201907001 80 97 70
kk:      201907002 90 97 90
hh 201907003 60 67 60
jj 201907004 59 57 58
aa 201907005 23 34 12

使用一個或多個空格,一個或多個冒號,一個或多個冒號和空格的組合進行文本的分割:

[root@172-0-10-222 shell-test]# cat testfile | awk -F '[: ]+' '{print $1}'
ll
kk
hh
jj
aa

案例:獲取本機ip

查看ip信息如下:

[root@172-0-10-222 shell-test]# ip a
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN group default qlen 1000
    link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
    inet 127.0.0.1/8 scope host lo
       valid_lft forever preferred_lft forever
    inet6 ::1/128 scope host 
       valid_lft forever preferred_lft forever
2: ens32: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast state UP group default qlen 1000
    link/ether 00:50:56:87:37:a9 brd ff:ff:ff:ff:ff:ff
    inet 172.0.10.222/16 brd 172.0.255.255 scope global noprefixroute ens32
       valid_lft forever preferred_lft forever
    inet6 fe80::2dea:8641:fee:950f/64 scope link noprefixroute 
       valid_lft forever preferred_lft forever

使用awk獲取ip:

[root@172-0-10-222 shell-test]# ip a | grep 'scope global' | awk -F '[ /]+' '{print $3}'
172.0.10.222

(2)awk的內置變量NF

NF(number of field)表示當前行被分割後的字段(列)數。

測試文件如下:

[root@172-0-10-222 shell-test]# cat testfile 
 ll 201907001 80 97 70
 kk 201907002 90 97 90
 hh 201907003 67 60
 jj 201907004 59 57 58
 aa 201907005    12

使用NF獲取每一行被分割後的字段數

[root@172-0-10-222 shell-test]# cat testfile | awk '{print NF}'
5
5
4
5
3

輸出每行最後一列的數據

[root@172-0-10-222 shell-test]# cat testfile | awk '{print $NF}'
70
90
60
58
12

輸出每行倒數第二列的數據

[root@172-0-10-222 shell-test]# cat testfile | awk '{print $(NF-1)}'
97
97
67
57
201907005

(3)awk的內置變量NR和FNR

NR(number of record)表示行號,FNR可以將多個文件的行號獨立排序。

測試文件:

[root@172-0-10-222 shell-test]# cat testfile 
 ll 201907001 80 97 70
 kk 201907002 90 97 90
 hh 201907003 67 60
 jj 201907004 59 57 58
 aa 201907005    12

使用NR打印行號:

[root@172-0-10-222 shell-test]# cat testfile | awk '{print NR}'
1
2
3
4
5

分別使用NR和FNR打印多個文件的整體行號和獨立行號:

測試文件如下:

[root@172-0-10-222 shell-test]# cat testfile
 ll 201907001 80 97 70
 kk 201907002 90 97 90
 hh 201907003 67 60
 jj 201907004 59 57 58
 aa 201907005    12
[root@172-0-10-222 shell-test]# cat testfile2 
 ll 201907001 80 97 70
 hh 201907003 67 60
 aa 201907005    12

NR輸出多個文件的整體行號

[root@172-0-10-222 shell-test]# awk '{print NR}' testfile testfile2
1
2
3
4
5
6
7
8

FNR輸出多個文件的獨立行號

[root@172-0-10-222 shell-test]# awk '{print FNR}' testfile testfile2
1
2
3
4
5
1
2
3

一般情況下,FNR不常用。

NR的常用用法:輸出指定的行。

例如:輸出testfile的第三行

[root@172-0-10-222 shell-test]# awk 'NR==3{print}' testfile
 hh 201907003 67 60

輸出testfile的第2行到第四行

[root@172-0-10-222 shell-test]# awk 'NR>=2&&NR<=4{print}' testfile
 kk 201907002 90 97 90
 hh 201907003 67 60
 jj 201907004 59 57 58

注意:awk的執行過程是pattern{action}方式,就是單引號中的輸出方式是滿足條件後輸出。比如上面的'NR>=2&&NR<=4{print}',表示行號是2到4的行輸出。可以使用這種方式,靈活輸出滿足條件的任意列。

(4)awk中使用BEGIN和END

BEGIN和END分別在awk的正常輸出之前和之後做一些事情。所謂的之後,就是在awk執行完每一行結束後。

測試文件入下:

[root@172-0-10-222 shell-test]# cat testfile
 ll 201907001 80 97 70
 kk 201907002 90 97 90
 hh 201907003 67 60
 jj 201907004 59 57 58
 aa 201907005    12

輸出文件的2-4行,並且在前面加上========begin========,在後面加上========end========

[root@172-0-10-222 shell-test]# awk 'BEGIN{print "========begin========"}NR>=2&&NR<=4{print $0}END{print "========end========"}' testfile
========begin========
 kk 201907002 90 97 90
 hh 201907003 67 60
 jj 201907004 59 57 58
========end========

通常,BEGIN可以用來做變量賦值。

(5)awk中的計算

測試文件:

[root@172-0-10-222 shell-test]# cat testfile
 ll 201907001 80 97 70
 kk 201907002 90 97 90
 hh 201907003 67 60 77
 jj 201907004 59 57 58
 aa 201907005 89 62 63

將每一行的後三列之和放在最後一列

[root@172-0-10-222 shell-test]# cat testfile | awk '{print $0,$3+$4+$5}'
 ll 201907001 80 97 70 247
 kk 201907002 90 97 90 277
 hh 201907003 67 60 77 204
 jj 201907004 59 57 58 174
 aa 201907005 89 62 63 214

再將每一行的後三列的平均數放在最後一列

[root@172-0-10-222 shell-test]# cat testfile | awk '{sum=$3+$4+$5;print $0,sum,sum/3}'
 ll 201907001 80 97 70 247 82.3333
 kk 201907002 90 97 90 277 92.3333
 hh 201907003 67 60 77 204 68
 jj 201907004 59 57 58 174 58
 aa 201907005 89 62 63 214 71.3333

後三列,計算每行之和

[root@172-0-10-222 shell-test]# cat testfile | awk '{a+=$3;b+=$4;c+=$5}END{print a,b,c}'
385 373 358

案例:統計/usr/bin/下面的所有進程佔CPU和內存的百分比。

/usr/bin/下面的所有進程的情況:

[root@172-0-10-222 shell-test]# ps -aux | grep /usr/bin/
dbus       643  0.0  0.1  66432  2588 ?        Ssl  Nov06   0:03 /usr/bin/dbus-daemon --system --address=systemd: --nofork --nopidfile --systemd-activation
root       646  0.0  0.3  99656  6112 ?        Ss   Nov06   0:00 /usr/bin/VGAuthService -s
root       647  0.1  0.3 298660  6172 ?        Ssl  Nov06  17:05 /usr/bin/vmtoolsd
root      1013  0.0  0.9 573852 17004 ?        Ssl  Nov06   2:04 /usr/bin/python -Es /usr/sbin/tuned -l -P
root     10245  0.0  0.0 112704   972 pts/1    S+   14:08   0:00 grep --color=auto /usr/bin/

第三列和第四列分別是CPU和內存,所以將這兩列的每行相加即可

[root@172-0-10-222 shell-test]# ps -aux | grep /usr/bin/ | awk '{cpu+=$3;mem+=$4}END{print cpu,mem}'
0.1 1.6

(6)awk中if的使用

if判斷,跟之前的pattern{action}模式功能類似。

測試目錄:

[root@172-0-10-222 shell-test]# ll
total 100
-rw-r--r--. 1 root root    0 Oct 21 19:20 4]]
-rw-r--r--. 1 root root 6048 Nov 13 16:19 dataMigration_part1.sh
-rwxr-xr-x. 1 root root 1059 Nov 13 15:10 dataMigration_part2.sh
-rwxr-xr-x. 1 root root  104 Oct 21 19:19 expr_test.sh
-rwxr-xr-x. 1 root root  161 Oct 16 20:22 input_test.sh
drwxr-xr-x. 2 root root    6 Nov  6 14:02 ipconf
-rw-r--r--. 1 root root  160 Nov  6 11:22 ip.txt
-rwxr-xr-x. 1 root root   94 Oct 18 17:36 let_test2.sh
-rwxr-xr-x. 1 root root  229 Oct 18 17:26 let_test.sh
-rwxr-xr-x. 1 root root 1107 Nov 12 11:31 modifyDir.sh
-rw-r--r--. 1 root root  738 Nov 13 09:00 modifyNfsConfiguration.sh
-rw-r--r--. 1 root root 2798 Nov 13 11:59 modifyShareConfiguration.sh
drwxr-xr-x. 2 root root  197 Nov 11 14:15 myfolder
-rw-r--r--. 1 root root   17 Nov 12 20:24 test
-rwxr-xr-x. 1 root root  243 Nov  6 11:05 test_break_continue.sh
-rwxr-xr-x. 1 root root  234 Oct 30 11:23 test_case.sh
-rw-r--r--. 1 root root   76 Oct 16 20:22 test.cnf
-rw-r--r--. 1 root root  115 Nov 14 13:44 testfile
-rw-r--r--. 1 root root   63 Nov 14 10:49 testfile2
-rwxr-xr-x. 1 root root  241 Oct 31 19:34 test_for.sh
-rwxr-xr-x. 1 root root  395 Oct 30 11:17 test_if.sh
-rw-r--r--. 1 root root   84 Nov 13 14:23 test.sh
-rwxr-xr-x. 1 root root   78 Oct 31 19:57 test_while_case.sh
-rwxr-xr-x. 1 root root  367 Nov  6 13:59 test_whilereadline2.sh
-rwxr-xr-x. 1 root root  313 Nov  6 11:38 test_whilereadline.sh
-rwxr-xr-x. 1 root root  217 Oct 31 19:53 test_while.sh
-rwxr-xr-x. 1 root root  254 Oct 31 20:19 test_xunhuan_case.sh

查詢出指定目錄下,大於1K的所有文件。

[root@172-0-10-222 shell-test]# ll | awk '/^-/{if($5>1024){print $0}}'
-rw-r--r--. 1 root root 6048 Nov 13 16:19 dataMigration_part1.sh
-rwxr-xr-x. 1 root root 1059 Nov 13 15:10 dataMigration_part2.sh
-rwxr-xr-x. 1 root root 1107 Nov 12 11:31 modifyDir.sh
-rw-r--r--. 1 root root 2798 Nov 13 11:59 modifyShareConfiguration.sh

(7)awk的for循環

測試文件:

[root@172-0-10-222 shell-test]# cat testfile
 ll 201907001 80 97 70
 kk 201907002 90 97 90
 hh 201907003 67 60 77
 jj 201907004 59 57 58
 aa 201907005 89 62 63

循環輸出按照默認分隔符(空格)分割得到的數據

[root@172-0-10-222 shell-test]# cat testfile | awk '{for(i=1;i<=NF;i++){print $i}}'
ll
201907001
80
97
70
kk
201907002
90
97
90
hh
201907003
67
60
77
jj
201907004
59
57
58
aa
201907005
89
62
63

如果想在上面輸出數據的基礎上,打印成最開始文件的內容格式,可以採用如下做法

[root@172-0-10-222 shell-test]# cat testfile | awk '{for(i=1;i<=NF;i++){printf $i" "}print xxoo}'
ll 201907001 80 97 70 
kk 201907002 90 97 90 
hh 201907003 67 60 77 
jj 201907004 59 57 58 
aa 201907005 89 62 63 

其中,print xxoo表示打印一個空變量,效果就相當於空行。也可以寫print ""或者print " "都行。

(8)awk中使用正則表達式

在awk中使用正則表達式,基本都是用來匹配條件,然後進行打印輸出的。因此,使用正則的位置通常都是在if條件中(或者前面說的patten位置)。

測試文件:

[root@172-0-10-222 shell-test]# cat testfile
ll 201907001 80 97 70
kk 201907002 90 97 90
hh 201908003 67 60 77
jj 201908004 59 57 58
aa 201909005 67 82 63

a)輸出第二行以後的所有行

[root@172-0-10-222 shell-test]# cat testfile | awk 'NR>=2{print $0}'
kk 201907002 90 97 90
hh 201908003 67 60 77
jj 201908004 59 57 58
aa 201909005 67 82 63

或者寫成:cat testfile | awk '{if(NR>=2){print $0}}'

b)使用正則表達式過濾出包含8的行

[root@172-0-10-222 shell-test]# cat testfile | awk '/8/&&NR>=2{print $0}'
hh 201908003 67 60 77
jj 201908004 59 57 58
aa 201909005 67 82 63

或者寫成:cat testfile | awk '/8/{if(NR>=2){print $0}}'

c)對上述結果過濾出第二列包含8的行

[root@172-0-10-222 shell-test]# cat testfile | awk '$2~/8/&&/8/&&NR>=2{print $0}'
hh 201908003 67 60 77
jj 201908004 59 57 58

也可以這樣寫:cat testfile | awk '$2~/8/&&/8/{if(NR>=2){print $0}}'

 

發佈了71 篇原創文章 · 獲贊 5 · 訪問量 6453
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章