文本處理工具awk
awk的名字由來:創始人Aho, Weinberger, Kernighan三人的首字母
有多種版本:New awk(nawk),GNU awk(gawk)
一.gawk 模式掃描和處理語言
基本用法:
awk [options] ‘program’ var=value file…
awk [options] -f programfile var=value file…
awk [options] 'BEGIN{ action;… } pattern{ action;… } END{
action;… }' file …
注:awk 程序通常 由:BEGIN 語句 塊、能夠使用模式匹配的通用語句塊、END 語句塊,共3 部分 組成program 通常是被單引號或雙引號中
選項:
-F 指明輸入時用到的字段分隔符
-v var=value: 自定義變量
-f scrifile :調用awk命令
基本格式:
awk [options] 'program' file…
program:pattern{action statements;..}
pattern 和action: :
? pattern 部分決定動作語句何時觸發及觸發事件(BEGIN,END)
? action statements對 對 數據進行處理,放在{} 內指明(print, printf)
分割符、域和記錄
? awk 執行時,由分隔符分隔的字段(域)標記$1,$2..$n稱為域標識。$0為所有域。
注意:和shell中變量$符含義不同
? 文件的每一行稱為記錄
? 省略action行,則默認執行print $0的操作
print 格式:print item1, item2, …
要點 :
? (1) 逗號分隔符
? (2) 輸出的各item 可以字符串,也可以是數值;當前記錄的字段 、變量或awk的表達式
? (3) 如省略item ,相當于print $0
例1:打印hello awk 用/etc/issue的行
[root@lxc ~]# awk '{print "hello awk"}' /etc/issue
hello awk
hello awk
hello awk
[root@lxc ~]#
例2:顯示系統中所有的用戶名和UID
[root@lxc ~]# awk -F: '{print $1 "\t" $3}' /etc/passwd
root 0
bin 1
daemon 2
adm 3
lp 4
sync 5
……
二.awk變量
變量:內置和自定義變量
FS:輸入字段分隔符,默認為空白字符
例:
[root@lxc ~]# awk -v FS=":" '{print $1,FS,$3}' /etc/passwd
root : 0
bin : 1
daemon : 2
adm : 3
lp : 4
sync : 5
……
OFS:輸出字段分隔符,默認為空白字符
例:
[root@lxc ~]# awk -v FS=":" -v OFS="====" '{print $1,$3}' /etc/passwd
root====0
bin====1
daemon====2
adm====3
lp====4
sync====5
shutdown====6
……
RS :輸入記錄分隔符,指定輸入時的換行符原換行符仍有效
例:
[root@lxc ~]# cat test.txt
a b c
dd ee ff
gg
[root@lxc ~]# awk -v RS=" " '{print $1}' test.txt
a
b
c
ee
ff
[root@lxc ~]#
ORS :輸出記錄分隔符,輸出時用指定符號代替換行符
例:
[root@lxc ~]# awk -v RS=" " -v ORS="=" '{print $1}' test.txt
a=b=c=ee=ff=[root@lxc ~]# cat test.txt
a b c
dd ee ff
gg
[root@lxc ~]#
NF :字段數量
例1:打印字段數量
[root@lxc ~]# awk -F: '{print NF}' /etc/passwd
7
7
7
7
7
……
例2:顯示最后一個字段
[root@lxc ~]# awk -F: '{print $NF}' /etc/passwd
/bin/bash
/sbin/nologin
/sbin/nologin
/sbin/nologin
/sbin/nologin
……
NR :行號
例:
[root@lxc ~]# awk -F: '{print NR}' /etc/passwd
1
2
3
4
5
6
……
FNR :各文件分別計數, 行號
例:
[root@lxc ~]# awk '{print FNR}' test.txt /etc/issue
1
2
3
1
2
3
[root@lxc ~]#
FILENAME :當前文件名
例:
[root@lxc ~]# awk -F: '{print FNR,FILENAME,$1}' /etc/issue test.txt
1 /etc/issue CentOS release 6.8 (Final)
2 /etc/issue Kernel \r on an \m
3 /etc/issue
1 test.txt a b c
2 test.txt dd ee ff
3 test.txt gg
[root@lxc ~]#
ARGC :命令行參數的個數
[root@lxc ~]# awk '{print ARGC}' /etc/fstab /etc/inittab
3
3
3
……
ARGV :數組,保存的是命令行所給定的各參數(不理解)
例:
[root@lxc ~]# awk 'BEGIN {print ARGV[0]}' /etc/fstab
awk
[root@lxc ~]#
自定義變量
(1) -v var=value 變量名區分字符大小寫
(2) 在program中直接定義
例1:
[root@lxc ~]# awk -F: -v name="username" -v uid="uid" '{print name":"$1,"\t"uid":"$3}' /etc/passwd
username:root uid:0
username:bin uid:1
username:daemon uid:2
username:adm uid:3
username:lp uid:4
……
例2:
[root@lxc ~]# awk -F: '{n="haha";m="xixi";print n,m}' /etc/passwd
haha xixi
haha xixi
haha xixi
haha xixi
haha xixi
……
三.printf命令
格式化輸出:printf “FORMAT ”, item1, item2, …
(1) 必須指定FORMAT
(2) 不會自動換行,需要顯式給出換行控制符,\n
(3) FORMAT 中需要分別為后面每個item 指定格式符
格式符:與item 一一對應
%c: 顯示字符的ASCII碼 碼
%d, %i: 顯示十進制整數
%e, %E: 顯示科學計數法數值
%f :顯示為浮點數
%g, %G :以科學計數法或浮點形式顯示數值
%s :顯示字符串
%u :無符號整數
%%: 顯示%自身
修飾符:
#[.#] :第一個數字控制顯示的寬度;第二個# 表示小數點后精度,%3.1f
-: 左對齊(默認) 右對齊) %-15s
+ :顯示數值的號 正負符號 %+d
例1:
[root@lxc ~]# awk -F: '{printf "%s %d\n",$1,$3}' /etc/passwd
root 0
bin 1
daemon 2
adm 3
lp 4
sync 5
……
例2:
[root@lxc ~]# awk -F: '{printf "%s\n",$1}' /etc/passwd
root
bin
daemon
adm
lp
……
例3:
[root@lxc ~]# awk -F: '{printf "username: %s\n",$1}' /etc/passwd
username: root
username: bin
username: daemon
……
例4:
[root@lxc ~]# awk -F: '{printf "username: %15s,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
……
例5:
[root@lxc ~]# awk -F: '{printf "username: %-15s,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
……
四.操作符
算術操作符:
x+y, x-y, x*y, x/y, x^y, x%y
-x: 轉換為負數
+x: 轉換為數值
字符串操作符:沒有符號的操作符,字符串連接
賦值操作符:=, +=, -=, *=, /=, %=, ^=,++, —
例:
[root@lxc ~]# awk 'BEGIN{n=1;m=2;print m+=n}'
3
[root@lxc ~]#
比較操作符:>, >=, <, <=, !=, ==
例:
[root@lxc ~]# awk -F: '$3 > 1000 {print $1,$3}' /etc/passwd
nfsnobody 65534
[root@lxc ~]#
模式匹配符:
~ :左邊是否和右邊匹配包含
!~ :是否不匹配
例:
[root@lxc ~]# awk '$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@lxc ~]# awk -F: '!($3==0 || $3 >=1000){print $1,$3}' /etc/passwd
bin 1
daemon 2
adm 3
lp 4
sync 5
shutdown 6
……
函數調用:function_name(argu1, argu2, …)
條件表達式(三目表達式):
selector?if-true-expression:if-false-expression
例:
[root@lxc ~]# awk -F: '{$3>=1000?usertype="Commom user":usertype="susadmin sysuser";printf"%15s:%-s\n",$1,usertype}' /etc/passwd
root:susadmin sysuser
bin:susadmin sysuser
daemon:susadmin sysuser
adm:susadmin sysuser
lp:susadmin sysuser
sync:susadmin sysuser
shutdown:susadmin sysuser
……
PATTERN: 根據pattern 條件,過濾匹配的行,再做處理
(1) 如果未指定:空模式,匹配每一行
(2) /regular expression/:僅處理能夠模式匹配到的行,需要用/ /括起來
(3) relational expression: 關系表達式,結果有“真”有“假”,結果為“真”才會被處理。
真:結果為非0值,非空字符串
假:結果為空字符串或0值
例1:結果為假不處理
[root@lxc ~]# awk '"" {print $0}' /etc/fstab
[root@lxc ~]#
例2:結果為真處理
[root@lxc ~]# awk '1{print $0}' /etc/fstab
#
# /etc/fstab
# Created by anaconda on Thu Nov 3 19:08:05 2016
#
# 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
……
例3:
[root@lxc ~]# awk -F: '$NF=="/bin/bash"{print $1,$NF}' /etc/passwd
root /bin/bash
lxc /bin/bash
[root@lxc ~]#
例4:
[root@lxc ~]# awk -F: '$NF!~"/bin/bash"{print $1,$NF}' /etc/passwd“
bin /sbin/nologin
daemon /sbin/nologin
adm /sbin/nologin
lp /sbin/nologin
sync /bin/sync
shutdown /sbin/shutdown
……
(4) line ranges:行范圍
startline,endline :/pat1/,/pat2/ 不支持直接給出數字格式
例1:
[root@lxc ~]# awk -F: '/^root/,/^lp/' /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
adm:x:3:4:adm:/var/adm:/sbin/nologin
lp:x:4:7:lp:/var/spool/lpd:/sbin/nologin
[root@lxc ~]#
例2:
[root@lxc ~]# awk -F: 'NR>=10 && NR<=15 {print NR,$0}' /etc/passwd
10 uucp:x:10:14:uucp:/var/spool/uucp:/sbin/nologin
11 operator:x:11:0:operator:/root:/sbin/nologin
12 games:x:12:100:games:/usr/games:/sbin/nologin
13 gopher:x:13:30:gopher:/var/gopher:/sbin/nologin
14 ftp:x:14:50:FTP User:/var/ftp:/sbin/nologin
15 nobody:x:99:99:Nobody:/:/sbin/nologin
[root@lxc ~]#
(5) BEGIN/END模式
BEGIN{}: 僅在開始處理文件中的文本之前執行一次
END{}:僅在文本處理完成之后執行
例1:
[root@lxc ~]# awk -F: 'BEGIN{print "linenumber username"}NR>10&&NR<=15{print NR,$0}' /etc/passwd
linenumber username
11 operator:x:11:0:operator:/root:/sbin/nologin
12 games:x:12:100:games:/usr/games:/sbin/nologin
13 gopher:x:13:30:gopher:/var/gopher:/sbin/nologin
14 ftp:x:14:50:FTP User:/var/ftp:/sbin/nologin
15 nobody:x:99:99:Nobody:/:/sbin/nologin
[root@lxc ~]#
例2:
[root@lxc ~]# awk -F: 'BEGIN{print "linenumber username"}NR>10 && NR<=15{print NR,$0}END{print "end"}' /etc/passwd
linenumber username
11 operator:x:11:0:operator:/root:/sbin/nologin
12 games:x:12:100:games:/usr/games:/sbin/nologin
13 gopher:x:13:30:gopher:/var/gopher:/sbin/nologin
14 ftp:x:14:50:FTP User:/var/ftp:/sbin/nologin
15 nobody:x:99:99:Nobody:/:/sbin/nologin
end
[root@lxc ~]#
例3:
[root@lxc ~]# seq 10 | awk 'i=0'
[root@lxc ~]# seq 10 | awk 'i=1'
1
2
3
4
5
6
7
8
9
10
[root@lxc ~]# seq 10 | awk 'i=!i'
1
3
5
7
9
[root@lxc ~]# seq 10 |awk '{i=!i;print i}'
1
0
1
0
1
0
1
0
1
0
[root@lxc ~]# seq 10 |awk '!(i=!i)'
2
4
6
8
10
[root@lxc ~]# seq 10 |awk -v i=1 'i=!i'
2
4
6
8
10
[root@lxc ~]#
五.awk 控制語句
{ statements;… } 組合語句
if(condition) {statements;…}
if(condition) {statements;…} else {statements;…}
while(conditon) {statments;…}
do {statements;…} while(condition)
for(expr1;expr2;expr3) {statements;…}
break
continue
delete array[index]
delete array
exit
if-else
語法:if(condition) statement [else statement]
if(condition1){statement1}else if(condition2){statement2}
else{statement3}
使用場景:對awk取得的整行或某個字段做條件判斷
例1:顯示普通用戶的用戶名和UID
[root@lxc ~]# awk -F: '{if ($3>=500) print $1,$3}' /etc/passwd
nfsnobody 65534
lxc 500
[root@lxc ~]#
例2:顯示磁盤利用率超過80%的
[root@lxc ~]# df -h |awk -F% '/^\/dev/{print $1}'|awk '{if($NF>80)print $1,$5}'
[root@lxc ~]#
例3:判斷成績
[root@lxc ~]# awk 'BEGIN{test=100;if(test>90){print "very good"}else if(test>60){prin t good""}else{print "no pass"}}'
very good
[root@lxc ~]#
while 循環
語法:while(condition){statement;…}
條件“真”,進入循環;條件“假”, 退出循環
使用場景:對一行內的多個字段逐一類似處理時使用
對數組中的各元素逐一處理時使用
例:顯示文件中以linux16為行首(行首可有空格)的行中的各個字段及所字段字符串的長度
[root@localhost ~]# awk '/^[[:space:]]*linux16/{i=1;while(i<=NF) {if(length($i)>=10)> {print $i,length($i)}; i++}}' /etc/grub2.cfg
/vmlinuz-3.10.0-327.el7.x86_64 30
root=/dev/mapper/centos-root 28
crashkernel=auto 16
rd.lvm.lv=centos/root 21
rd.lvm.lv=centos/swap 21
net.ifnames=0 13
/vmlinuz-0-rescue-0dc32f41d52e4e3a9bd9a30a2683ae5d 50
root=/dev/mapper/centos-root 28
crashkernel=auto 16
rd.lvm.lv=centos/root 21
rd.lvm.lv=centos/swap 21
net.ifnames=0 13
[root@localhost ~]#
do-while 循環
語法:do {statement;…}while(condition)
意義:無論真假,至少執行一次循環體
例:1~100的自然數的和
[root@lxc ~]# awk 'BEGIN{sum=0;i=0;do{sum+=i;i++;}while(i<=100);print sum}'
5050
[root@lxc ~]#
for 循環
語法:for(expr1;expr2;expr3) {statement;…}
常見用法:
for(variable assignment;condition;iteration process)
{for-body}
特殊用法:能夠遍歷數組中的元素;
語法:for(var in array) {for-body}
例:1~100的自然數的和
[root@lxc ~]# awk 'BEGIN{total=0;for(i=1;i<=100;i++){total+=i}{print total}}'
5050
[root@lxc ~]#
例2:
1~100之間的奇數之和
[root@lxc ~]# awk 'BEGIN{sum=0;for(i=1;i<=100;i++){if(i%2==1)continue;sum+=i};print sum}'
2550
[root@lxc ~]#
switch 語句
語法: :switch(expression) {case VALUE1 or /REGEXP/:
statement1; case VALUE2 or /REGEXP2/: statement2;
…; default: statementn}
break 和continue
例:
[root@lxc ~]# awk 'BEGIN{sum=0;for(i=1;i<=100;i++){if (i%2==0)break;sum+=i}print sum}'
1
[root@lxc ~]#
next:提前結束對本行處理而直接進入下一行處理(awk自身循環)
例:
[root@lxc ~]# awk -F: '{if ($3%2==0)netx;print$1,$3}' /etc/passwd
root 0
bin 1
daemon 2
adm 3
lp 4
……
六.awk數組
關聯數組:array[index-expression]
index-expression:
(1) 可使用任意字符串;字符串要使用雙引號括起來
(2) 如果某數組元素事先不存在,在引用時,awk 會自動創建此元素,并將其值初始化為“空串”
注:若要判斷數組中是否存在某元素,要使用“index in array”格式進行遍歷
例1:
[root@lxc ~]# awk 'BEGIN{arr["frist"]="mage";arr["second"]="laowang";print arr["frist"]}'
mage
[root@lxc ~]#
例2:
[root@lxc~]# awk' BEGIN{weekdays["mon"]="Monday";weekdays["tue"]="Tuseday";for(i in weekdays){print weekdays[i]}}'
Monday
Tuseday
[root@lxc ~]#
數值處理:
rand():返回0和1之間一個隨機數
[root@lxc ~]# awk 'BEGIN{srand();for (i=1;i<=5;i++)print int(rand()*100)}'
5
17
68
52
49
[root@lxc ~]#
字符串處理:
? length([s]) :返回指定字符串的長度
? sub(r,s,[t]) :對t字符串進行搜索r表示的模式匹配的內容,并將第一個匹配的內容替換為s
例:
[root@lxc ~]# echo "2008:08:08 08:08:08" | awk 'sub(/:/,"-",$1)'
2008-08:08 08:08:08
[root@lxc ~]#
? gsub(r,s,[t]) :對t字符串進行搜索r表示的模式匹配的內容,并全部替換
為s所表示的內容
例:
[root@lxc ~]# echo "2008:08:08 08:08:08" | awk 'gsub(/:/,"-")'
2008-08-08 08-08-08
[root@lxc ~]#
? split(s,array,[r]) :以r 為分隔符,切割字符s,并將切割后的結果保存至array所表示的數組中,第一個索引值為1, 第二個索引值為2,…
例:
[root@lxc ~]# netstat -tan |awk '/^tcp\>/{split($5,ip,":");count[ip[1]]++}END{for (i in count){print i,count[i]}}'
7
172.16.253.83 1
0.0.0.0 6
[root@lxc ~]#
自定義函數
格式:
function name ( parameter, parameter, … ) {
statements
return expression
}
例:
[root@lxc ~]# cat fun.awk
function funmin(num1,num2){
num1<num2?min=num1:min=num2
return min
}
BEGIN{n1=100; n2=200;print funmin(n1,n2)}
[root@lxc ~]# awk -f fun.awk
100
[root@lxc ~]#
system 命令
空格是awk中的字符串連接符,如果system中需要使用awk中的變量可以使用空格分隔,或者說除awk的變量外其他一律用""引用起來。
例:
[root@lxc ~]# awk 'BEGIN{score=100;system("echo your score is " score)}'
your score is 100
[root@lxc ~]#
將awk程序寫成腳本,直接調用或執行
例:
[root@lxc ~]# cat f1.awk
#!/bin/awk -f
{if($3>=1000)print $1,$3}
[root@lxc ~]# ./f1.awk -F: /etc/passwd
nfsnobody 65534
[root@lxc ~]#
向腳本傳遞參數
格式:awkfile var=value var2=value2… Inputfile
例:
[root@lxc ~]# cat test.awk
#!/bin/awk -f
{if ($3>=min && $3<=max)print $1,$3}
[root@lxc ~]# ./test.awk -F: min=100 max=200 /etc/passwd
usbmuxd 113
avahi-autoipd 170
abrt 173
[root@lxc ~]#
原創文章,作者:changge,如若轉載,請注明出處:http://www.www58058.com/61516