AWK常見用法(一)

一、初識AWK

AWK有其他的衍生版本,比如nawkgawk,在Linux發行版裏,默認使用的是gawk:

# ls -l `which awk`
lrwxrwxrwx. 1 root root 4 5月   9 20:25 /usr/bin/awk -> gawk

二、AWK的工作流程

  • AWK是按行處理文本,將行按照某一分隔符進行分割,其中分割之後的第一部分爲$1,第二部分爲$2,依次類推,其中$0表示整行,超過10的要將數字用括號括起來,比如$(10)
  • AWK默認的分隔符是空格和tab,其中操作命令必須寫在{}裏面,語法:
awk '/模式/{print $1}' file     //模式支持正則表達式,只對含有該模式的行進行操作
  • 可以使用-F選項指定分隔符:
awk -F: '/模式/{print $1}' file

三、常見操作符的使用(例子中passwd文件使用/etc/passwd文件的前6行)

常見的操作符有:~!~==!=><++--

  1. ~!~表示包含和不包含:
# awk -F: '$1~/ro/{print $0}' passwd 
root:x:0:0:root:/root:/bin/bash
  1. ==!=表示嚴格的等於和不等於:
# awk -F: '$3==1{print $0}' passwd 
bin:x:1:1:bin:/bin:/sbin/nologin
# awk -F: '{$3++;print $3}' passwd 
1
2
3
4
5
6
  1. 其他的一些操作符同理,兩個以上的條件需要使用連接符&&||

四、AWK中 BEGIN 和 NED 的用法

  1. BEGIN中的命令是在AWK讀取文本的第一行之前進行操作:
# awk -F: 'BEGIN{print "用戶名"}{print $1}' passwd 
用戶名
root
bin
daemon
adm
lp
sync
  1. END中的命令是在讀取完最後一行之後進行的操作:
# awk -F: '{print $1}END{print "結束"}' passwd 
root
bin
daemon
adm
lp
sync
結束
  1. BEGIN和END可以同時出現,也可以單獨出現,BEGIN中可以定義變量:
# awk -F: 'BEGIN{a=1}{print a}' passwd 
1
1
1
1
1
1

如何沒有預先定義變量的話,在後面也是可以引用的,只不過這個變量的值爲空。引用變量的時候不加$
END中也可以進行最終的計算:

# awk -F: 'BEGIN{sum=0}{sum+=$3}END{print "所有UID的和爲:"sum}' passwd 
所有UID的和爲:15

或者不預先定義變量:

# awk -F: '{sum+=$3}END{print "所有UID的和爲:"sum}' passwd 
所有UID的和爲:15

五、AWK中常見內置變量的用法

  1. FS代表分隔符:
# awk 'BEGIN{FS=":"}{print $1}' passwd 
root
bin
daemon
adm
lp
sync
  1. OFS爲打印輸出的分隔符,默認的是空格:
# awk 'BEGIN{FS=":";OFS="---"}{print $1,$2}' passwd 
root---x
bin---x
daemon---x
adm---x
lp---x
sync---x
  1. NF的值表示將每一行按照FS指定的分隔符分爲多少段:
# awk 'BEGIN{FS=":"}{print NF}' passwd 
7
7
7
7
7
7

如果要打印每一行的最後一段,可以使用以下用法:

# awk 'BEGIN{FS=":"}{print $NF}' passwd 
/bin/bash
/sbin/nologin
/sbin/nologin
/sbin/nologin
/sbin/nologin
/bin/sync
  1. 前面提到過,AWK是將文件按行進行處理,那麼AWK是如何分別每一行的呢?使用的就是RS的值,默認爲\n:
# cat test.txt 
1,張三:經理 2,李四:職員 3,王五:老闆
# awk -F[:,] 'BEGIN{RS=" "}{print $2,$3}' test.txt 
張三 經理
李四 職員
王五 老闆
  1. ORS變量的值決定輸出行的分隔符,默認的爲\n
# awk 'BEGIN{ORS="---"}{print $0}' 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---sync:x:5:0:sync:/sbin:/bin/sync---
  1. FILENAME變量的值爲當前操作文件的文件名:
# awk -F: '{print FILENAME}' passwd 
passwd
passwd
passwd
passwd
passwd
passwd
  1. NR變量的值表示當前正在操作的行號:
# awk -F: '{print NR}' passwd 
1
2
3
4
5
6

如果這裏將行分隔符RS賦值爲-,驗證NR的值:

# awk 'BEGIN{RS="-"}{print NR}' passwd 
1
  1. FNR也表示當前操作的行號,不同的是,當對一個文件進行操作的時候FNRNR的值是一樣的。當對兩個文件進行操作時,FNRNR的值是不一樣的:
# awk -F: '{print NR,$1,FNR}' passwd shadow 
1 root 1
2 bin 2
3 daemon 3
4 adm 4
5 lp 5
6 sync 6
7 root 1
8 bin 2
9 daemon 3
10 adm 4
11 lp 5
12 sync 6

六、判斷和循壞語句

  1. if語句:
    語法,如果語句沒有使用{},則要使用;分隔
if(判斷1){語句1}else if(判斷2){語句2}else{語句3}
if(判斷1)語句1;else if(判斷2)語句2;else語句3
# awk -F: '{if($3==0){print $1"是root"}else if($3>=1000){print $1"是普通用戶"}else{print $1"是系統用戶"}}' passwd 
root是root
bin是系統用戶
daemon是系統用戶
adm是系統用戶
lp是系統用戶
sync是系統用戶
  1. for循壞語句:
awk -F: '{for(i=1;i<=NF-5;i++){print $i}}' passwd 
root
x
bin
x
daemon
x
  1. while循壞語句:
# awk -F: '{print "------------";i=1;while(i<=NF){print $i;i++}}' 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. 循壞控制語句break
    break只能用在循環語句中,作用是跳出當前循環,繼續下一循環
# echo -e "1 2 3 4 1\n5 6 7" | awk '{for(i=1;i<=NF;i++){if($i>=2){break}print $i}}'
1
  1. 循環控制語句continue:如果遇到continue,continue後面的語句不再執行,繼續下一個循環
# echo -e "1 2 3 4 1\n5 6 7" | awk '{for(i=1;i<=NF;i++){if($i>=2){continue}print $i}}'
1
1
  1. 循環控制語句next:遇到next,跳出循環,繼續下移循環,在循環語句中next和break語句效果一樣。區別在於,break和continue語句只能用於循環語句,next語句還可以用於其他語句,以下例子用於判斷語句
# echo -e "1 2 3 4 1\n5 6 7 1" | awk '{if($2<=2){next}print $0}'
5 6 7 1
# awk -F: 'NR==FNR{print NR,FILENAME,FNR;next}{print NR,FILENAME,FNR}' passwd shadow 
1 passwd 1
2 passwd 2
3 passwd 3
4 shadow 1
5 shadow 2
6 shadow 3

七、AWK中數組的使用

  1. 手動定義數組
# echo '' | awk '{aa[1]=1;aa[2]=2;aa["b"]="b";print aa[1]}'
1
  1. 讀取文件
# awk -F: '{for(i=1;i<=NF;i++){a[i]=$i;print a[1];break}}' passwd 
root
bin
daemon
# cat c1
01 北京
02 上海
03 廣州
04 深圳
# cat c2
01 beijing
02 shanghai
03 guangzhou
04 shenzhen
# awk 'NR==FNR{a[$1]=$0}NR!=FNR{print a[$1],$2}' c1 c2
01 北京 beijing
02 上海 shanghai
03 廣州 guangzhou
04 深圳 shenzhen

八、AWK中常見函數的使用

  1. subgsub函數:用來替換
# cat test.txt 
tom bob mary tom
bob tom mary tom
# awk '{sub("tom","TOM");print}' test.txt 
TOM bob mary tom
bob TOM mary tom

但是隻替換了每行的第一個,要想替換所有的,使用gsub函數:

# awk '{gsub("tom","TOM");print}' test.txt 
TOM bob mary TOM
bob TOM mary TOM

只替換最後一個:

# awk '{gsub("tom","TOM",$NF);print}' test.txt 
tom bob mary TOM
bob tom mary TOM
  1. length函數用來計算字符串長度
# awk -F: '{print $1,length($1)}' passwd 
root 4
bin 3
daemon 6
  1. substr函數用來截取一段數據
# awk -F: '{print substr($1,2)}' passwd 
oot
in
aemon
# awk -F: '{print substr($1,2,2)}' passwd 
oo
in
ae
  1. match函數的使用,從字符串中匹配滿足某種格式的位置
# awk -F: '{xx=match($1,"oo");print xx}' passwd 
2
0
0

match中有兩個變量,RSTART可以獲取到match得到的值,RLENGTH表示的是match中滿足格式的字符創的長度,一般會結合substr截取我們所需要的數據:

# awk -F: '{xx=match($1,"oo");print xx,RSTART,RLENGTH}' passwd 
2 2 2
0 0 -1
0 0 -1
  1. split函數的使用:split("原始字符串",數組名,<分隔符>)
# echo '' | awk '{split("2018-05-20",xx,"-");print xx[1],xx[2],xx[3]}'
2018 05 20
# awk '{split($0,xx,":");print xx[1]}' passwd 
root
bin
daemon
  1. getline函數可以讓我們使用操作系統命令,也可以讀取另一個文件內容
# awk '{getline;print $0}' c1
02 上海
04 深圳

可以看到getline將本文件的下一行賦值給當前的$0

# awk '{getline xx;print $0,xx}' c1
01 北京 02 上海
03 廣州 04 深圳

在這裏將下一行的值賦值給了getline後的變量xx,並沒有影響當前的$0

getline < file:該用法讀取file文件的一行賦值給當前的$0
getline xx < file:該用法讀取file文件的一行賦值給變量xx

# awk '{getline xx< "c2";print xx,$2}' c1
01 beijing 北京
02 shanghai 上海
03 guangzhou 廣州
04 shenzhen 深圳
# echo '' | awk '{"date"|getline xx;print xx}'
2018年 05月 20日 星期日 19:57:04 CST
# echo '' | awk '{while("ls /boot"|getline xx) print xx}'
config-3.10.0-327.el7.x86_64
grub2
initramfs-0-rescue-ba7506401e184ceea617517542f6b7c7.img
initramfs-3.10.0-327.el7.x86_64.img
initrd-plymouth.img
symvers-3.10.0-327.el7.x86_64.gz
System.map-3.10.0-327.el7.x86_64
vmlinuz-0-rescue-ba7506401e184ceea617517542f6b7c7
vmlinuz-3.10.0-327.el7.x86_64
# echo '' | awk '{print "請輸入:";getline name<"/dev/tty";print "你好:" name}'
請輸入:
tom
你好:tom

九、AWK的格式化輸出

  1. printf不帶換行符
# awk -F: '{printf "%-8s|%-5d\n",$1,$3}' passwd 
root    |0    
bin     |1    
daemon  |2

其中%-8s中的-8表示顯示寬度爲8個字符,-表示左對齊,+號表示右對齊
%d顯示的整數
%f顯示的是浮點數,%10.5f表示總共顯示十位。小數點後顯示5位
%e用科學計數法顯示

# echo '' | awk '{printf "%d\n",3*3.5}'
10
# echo '' | awk '{printf "%f\n",3*3.5}'
10.500000
# echo '' | awk '{printf "%-.10f\n",10/3}'
3.3333333333
# echo '' | awk '{printf "%e\n",3*3.5}'
1.050000e+01
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章