一、知識整理
1、awk報告生成器,格式化文本輸出
發明人:a.k.a. Aho,Kernighan,weinberger
awk程序通常由:BEGIN語句塊、能夠使用模式匹配的通用語句塊、END語句塊三部分組成。program通常是放在單引號或雙引號中。
基本用法:awk [] ‘program’ var=value fiel…
program:pattern{action statements;…}
pattern和action:pattern部分決定動作語句何時出發及觸發事件
如:(BEGIN,END)
action statements對數據進行處理,放在{}內指明
如:(print,printf)
awk [] -f programfile var=value file
awk [] ‘BEGIN{action;…} pattern{action;…} END{action;…}’ file…
2、分隔符、域和記錄
awk執行時,由分隔符分隔的字段標記$1,$2..成為域標識。$0為所有域,注意:和shell中變量$符含義不同。
文件的每一行稱為記錄
省略action,則默認執行print $0的操作。
3、readlink命令:查看文件是否為鏈接文件并顯示原文件,相對目錄。
[root@centos68 ~]# readlink /etc/rc3.d/K01smartd ../init.d/smartd
centos7中,在/usr/sbin/下的pidof是軟鏈接,不同的腳本軟鏈接的執行結果不同。原因是給的值不同時,觸發了不同的情況。例如:
[root@localhost ~]# bash 1 1 basename is:1 [root@localhost ~]# bash 1.sh 1 basename is:1.sh [root@localhost ~]# cat 1 #!/bin/bash echo 1 echo "basename is:`basename $0`"
4、布爾值是“真” True 或“假” False 中的一個。動作腳本也會在適當時將值 True 和 False 轉換為 1 和 0。布爾值經常與動作腳本語句中通過比較控制腳本流的邏輯運算符一起使用。
5、查看httpd的訪問記錄:
[root@centos68 ~]# cat /var/log/httpd/access_log 從其中取出訪問的地址及次數:
[root@centos68~]#awk '{ip[$1]++}END{for(i in ip){print i,ip[i]}}' /var/log/httpd/access_log 10.1.252.66 122
每行的第一個字段是IP地址,賦值數組,重復則加一。
二、命令詳解及事例
1、工作原理:第一步:執行BEGIN{action;…}語句塊中的語句;
第二步:從文件或標準輸入讀取一行,然后執行pattern{action;…}語句塊,它逐行掃描文件,從第一行到最后一行重復這個過程,直到文件全部被讀取完畢。
第三步:當讀至輸入流末尾時,執行END{action;…}語句塊。
BEGIN語句塊在awk開始從輸入流中讀取行之前被執行,這是一個可選的語句塊,比如變量的初始化、打印輸出表格的表頭等語句通常是可以寫在BEGIN語句塊中的。
END語句塊在awk從輸入流中讀取完所有的行之后被執行,比如打印所有行的分析結果這類信息匯總都是在END語句塊中完成,也是一個可選語句塊。
pattern語句塊中的通用命令是最重要的部分,也是可選的。如果沒提供pattern語句塊,則默認執行{print},即打印每一個讀取到的行,awk讀取的每一行都會執行該語句塊。
2、awk變量:內置和自定義變量
FS:輸入字符分隔符,默認為空白字符
OFS:輸出字段分隔符,默認空白字符
RS:輸入記錄分隔符,指定輸入時的換行符,原換行符仍有效
ORS:輸出記錄分隔符,輸出時用指定符號代替換行符
NF:字段數量,引用內置變量不用$
NR:行號
FNR:各文件分別計數,行號
FILENAME:當前文件名
ARGC:命令行參數的個數
ARGV:數組,保存的是命令行給定的各參數
[root@centos68 ~]# awk 'BEGIN{print ARGV[1]}' /etc/fstab /etc/fstab [root@centos68 ~]# awk 'BEGIN{print ARGV[0]}' /etc/fstab awk
自定義變量:-v VAR=VALUE 變量名區分字符大小寫;在program中直接定義
3、printf命令:
格式化輸出:printf “FORMAT”,item1,item2,..
必須指定FORMAT
不會自動換行,需要顯式各處換行控制符
FORMAT中需要分別為后面每個item指定格式符
格式符:與item一一對應
%c 顯式字符的ASCII碼
%d,%i 顯示十進制整數
%e,%E 顯示科學計數法數值
%f 顯示為浮點數
%g,%G 以科學計數法或浮點形式顯示數值
%s 顯示字符串
%u 無符號整數
%% 顯示%自身
修飾符:#[.#] 第一個數字控制顯示的寬度;第二個#表示小數點后精度
– 左對齊(默認右對齊)%-15s
+ 顯示數值的正負符號 %+d,0也會添加正號
4、算術操作符:x+y,x-y,x*y,x/y,x^y,x%y
-x:轉換為負數
+x:轉換為數值
字符串操作符:沒有符號的操作符,字符串連接
賦值操作符:
=,+=,-=,*=,/=,%=,^=
++,—
比較操作符:
>,>=,<,<=,!=,==
模式匹配符:
~:左邊是否和右邊匹配包含
!~:是否不匹配
邏輯操作符:&&,||,!
函數調用:
function_name(argu1,argu2,…)
條件表達式:
selector?if-true-expression:if-false-expression
[root@centos68 ~]# awk -F: '{$3>=1000?usertype="common user":usertype="sysadmin or sysuser";printf "%15s:%-s\n",$1,usertype}' /etc/passwd root:sysadmin or sysuser saslauth:sysadmin or sysuser postfix:sysadmin or sysuser rpcuser:sysadmin or sysuser nfsnobody:common user
5、PATTERN:根據pattern條件,過濾匹配的行,再做處理
①如果未指定:空模式,匹配每一行
②/ /:僅處理能夠模式匹配到的行
③relational expression:關系表達式;結果有真有假;結果為真時才會被處理
真:結果為非0值,非空字符串
假:結果為空字符串
[root@centos68 ~]# awk -F: '$NF~/bash$/{print $1,$NF}' /etc/passwd root /bin/bash mysql /bin/bash tom /bin/bash gejingyi /bin/bash user1 /bin/bash [root@centos68 ~]# seq 10 | awk 'i=!i' 1 3 5 7 9
首先讀取第一行數據,也就是1,然后進行模式匹配,i是一個未定義的量,默認初值為0,也就是i=!0,對0取反就是1,顯然0=0成立,為真,輸出第一行。在第二行時,i已經由0變為1,即為1=!1,取反就是1=0顯然不成立,為假,則第二行不輸出。依次推算,只輸出奇數行。若為awk ‘!(i=!i)’,即將每次判斷的真假取反,就會輸出偶數行。
[root@centos68 ~]# seq 10 | awk '!(i=!i)' 2 4 6 8 10
④line ranges 行范圍
startline,endline:/PAT1/,/PAT2/ 不支持直接給出數字格式。
[root@centos68 ~]# awk -F: '/^root/,/^nobody/{print $1}' /etc/passwd root bin daemon adm operator games gopher ftp nobody
⑤BEGIN/END模式:
BEGIN:僅在開始處理文件中的文本之前執行一次
END{}:僅在文本處理完成之后執行一次
[root@centos68 ~]# awk -F: 'BEGIN{print "USER UID \n----------"}{print $1,$3}END{print "========="}' /etc/passwd USER UID ---------- root 0 bin 1 daemon 2 =========
6、awk控制語句之if else
語法:if(condition1){statement1}else if(condition2){statement2}else{statement3}
[root@centos68 ~]# awk -F: '{if($3>=1000){printf "common user: %s\n",$1}else{printf "root or sysuser:%s\n",$1}}' /etc/passwd root or sysuser:root root or sysuser:bin common user: nfsnobody root or sysuser:haldaemon
while循環:
語法:while(condition) statement
[root@localhost ~]# awk '/^[[:space:]]*linux16/{i=1;while(i<=NF){print $i,length($i);i++}}' /etc/grub2.cfg linux16 7 /vmlinuz-3.10.0-327.el7.x86_64 30 root=/dev/mapper/centos-root 28 ro 2 crashkernel=auto 16 rd.lvm.lv=centos/root 21 rd.lvm.lv=centos/swap 21 rhgb 4 quiet 5 linux16 7
對匹配到的行處理,awk中默認用空格為分隔符,將每個單詞單獨統計字符長度并打印。
do while循環:
語法:do statement while(condition) 無論真假,至少執行一次循環體
[root@localhost ~]# awk 'BEGIN{total=0;i=0;do{total+=i;i++;}while(i<=100);print total}' 5050
for循環:
語法:for(expr1;expr2;expr3)statement for(variable assignment;condition;iteration process) {for-body}
特殊用法:能夠遍歷數組中的元素:
語法:for(var in array) {for-body}
[root@localhost ~]# awk '/^[[:space:]]*linux16/{for(i=1;i<=NF;i++){print $i,length($i)}}' /etc/grub2.cfg linux16 7 /vmlinuz-3.10.0-327.el7.x86_64 30 root=/dev/mapper/centos-root 28 ro 2 crashkernel=auto 16 rd.lvm.lv=centos/root 21 rd.lvm.lv=centos/swap 21 rhgb 4 quiet 5
7、性能測試:
[root@localhost ~]# time (awk 'BEGIN{total=0;for(i=0;i<=10000;i++){total+=i;};print total;}') 50005000 real 0m0.009s user 0m0.000s sys 0m0.009s [root@localhost ~]# time (total=0;for i in $(seq 10000);do total=$(($total+i));done;echo $total) 50005000 real 0m0.071s user 0m0.065s sys 0m0.008s
awk語法是c語言語法,執行速度更快。
8、switch語句:
語法:switch(expression) {case VALUE1 or /REGEXP/:statement;case VALUE2 or /REGEXP2/:statement;…;default:statement}
break和continue;退出循環和退出本次循環執行下一次循環。
[root@localhost ~]# awk 'BEGIN{sum=0;for(i=1;i<=100;i++){if(i%2==0){continue}sum+=i}print sum}' 2500 [root@centos68 ~]# awk 'BEGIN{sum=0;for(i=1;i<=100;i++){if(i==11){break}sum+=i}print sum}' 55 [root@centos68 ~]# seq 10 | tr "\n" "+" | grep -Eo ".*[[:digit:]]" | bc 55
next:提前結束對本行處理而進入下一行處理(awk自身循環)
[root@centos68 ~]# awk -F: '{if($3%2!=0) next;print $1,$3}' /etc/passwd root 0 daemon 2 lp 4 shutdown 6 mail 8 uucp 10 games 12 ftp 14 rpc 32
9、awk數組:
關聯數組:array[index-expression]
index-expression:①可使用任意字符串;字符串要使用雙括號
②如果某數組元素事先不存在,在引用時,awk會自動創建此元素,并將其值初始化為空
若要判斷數組中是否存在某元素,要使用“INDEX in array”格式進行遍歷,但是index在此處有特殊意義,使用i等代替。
[root@localhost shelltest]# awk 'BEGIN{weekdays["mon"]="monday";print weekdays["mon"]}' monday [root@localhost ~]# awk '!array[$0]++' testawk.txt a b c [root@localhost ~]# cat testawk.txt a b c a b c
為何上面的命令將重復的行去掉了呢?原因如下:首先,當讀入第一個字符a時,關聯數組array的以a為索引的值為空,即array[a]=0,將此取反為1,邏輯上為真,則輸出第一行,然后自相加為2。其次,當讀入第二個值b時,同理可知為1,array[c]也為1。當第二次讀入a時,因為array[a]的值已經為2,(邏輯)取反之后為0,邏輯上是假,則不會輸出,自相加最后為1。
[root@localhost ~]# awk '!a[$0]++;{print $0,a["a"],a["b"],a["c"]}' testawk.txt a a 1 b b 1 1 c c 1 1 1 a 2 1 1 b 2 2 1 c 2 2 2
注意:第一點,!的運算順序比++要更優先;第二點,++是在print之后才會執行。
若要遍歷數組中的每個元素,要使用for循環。
語法:for(var in array) {for-body}
10、數值處理:
rand() 返回0和1之間的一個隨機數。random返回的是一個0到(2^31 – 1)的long類型整數。rand返回的是一個0到RAND_MAX的int類型整數,沒有定義時為1,RAND_MAX至少為32767。還有一個srandom,這個函數是為random設置種子的,參數和srand一樣。rand和srand函數是linux c的內容。
[root@centos68 ~]# awk 'BEGIN{srand();for (i=1;i<=5;i++)print int(rand()*100)}' 14 7 26 55 90
沒有種子無法生成隨機數,是個固定值。
[root@centos68 ~]# awk 'BEGIN{print rand()}' 0.237788 [root@centos68 ~]# awk 'BEGIN{srand();print rand()}' 0.831959 [root@centos68 ~]# awk 'BEGIN{srand();print rand()}' 0.420602
字符串處理:
length([S]) 返回指定字符串長度
sub(r,s,[t]) 對t字符串進行搜索r表示的模式匹配的內容,并將第一個匹配的內容替換為S代表的字符串。
gsub([r,s,[t]]) 對t字符串進行搜索r表示的模式匹配的內容,并全部替換為s。
split(s,array,[r]) 以r為分割符切割字符s,并將切割后的結果存至array表示的數組中。
[root@centos68 ~]# echo "2008:08:08:08 08:08:08" | awk 'sub(/:/,"",$1)' 200808:08:08 08:08:08 [root@centos68 ~]# echo "2008:08:08:08 08:08:08" | awk 'gsub(/:/,"",$1)' 2008080808 08:08:08 [root@centos68 ~]# echo "2008:08:08:08 08:08:08" | awk 'gsub(/:/,"",$2)' 2008:08:08:08 080808 [root@centos68 ~]# netstat -tan | awk '/^tcp\>/{split($5,ip,":")count[ip[1]]++}END{for (i in count){print i,count[i]}}' 6 10.1.252.66 1 0.0.0.0 6
11、awk函數:
自定義函數:格式:function name(parameter,parameter,…){
statements
return expression
}
[root@centos68 ~]# cat fun.awk function max(v1,v2){ v1>v2?var=v1:var=v2 return var } END{a=3;b=2;print max(a,b);} [root@centos68 ~]# awk -f fun.awk fun.awk 3
12、awk腳本:將awk程序寫成腳本,頭部寫awk -f,直接調用或執行,也可同shell腳本一樣傳遞參數:
[root@centos68 ~]# ./f2.awk -F: /etc/passwd nfsnobody 65534 [root@centos68 ~]# cat f2.awk #!/bin/awk -f {if($3>=1000)print $1,$3}
13、awk中調用shell命令:system命令:
空格是awk中的字符串連接符,如果system中需要使用awk中的變量可以使用空格分隔,或者說除了awk的變量外其他一律用””引用起來。
awk BEGIN’{system(“hostname”)}’
awk ‘BEGIN{a=12;system(“echo ” a)}’ 使用echo時要加空格。
三、課后練習
1、統計/etc/fstab文件中每個文件系統類型出現的次數。
[root@centos68 ~]# awk '/^[^#]/{print $3}' /etc/fstab | sort | uniq -c 1 devpts 4 ext4 1 iso9660 1 proc 1 swap 1 sysfs 1 tmpfs [root@centos68 ~]# awk '/^[^#]/{split($3,array)count[array[1]]++}END{for(i in count){print i,count[i]}}' /etc/fstab devpts 1 swap 1 sysfs 1 proc 1 tmpfs 1 iso9660 1 ext4 4
2、統計/etc/fstab文件中每個單詞出現的次數。
[root@centos68 ~]# awk '{for(i=1;i<=NF;i++){print $i}}' /etc/fstab | sort | uniq -c 1 / 7 # 14 0 4 1 1 18 1 18:38:10 2 2 1 2016 1 Accessible 1 anaconda 1 and/or 1 are 1 blkid(8) 1 /boot 2 by 1 Created 9 defaults 1 /dev/cdrom 1 '/dev/disk' 2 devpts 1 /dev/pts 1 /dev/sda6 1 /dev/shm 1 /etc/fstab 4 ext4 1 filesystems, 1 findfs(8), 1 for 1 fstab(5), 1 gid=5,mode=620 1 /home 1 info 1 iso9660 1 Jul 1 maintained 1 man 1 /media/cdrom 1 Mon 1 more 1 mount(8) 1 on 1 pages 2 proc 1 /proc 1 reference, 1 See 2 swap 1 /sys 2 sysfs 1 /testdir 2 tmpfs 1 under 1 UUID=86ad06a2-cd08-4f18-b06b-98d7cb2e23df 1 UUID=aaad69ad-d716-4676-941f-851223ddab7f 1 UUID=aae1cc08-6344-4424-9275-cfc4d6569d95 1 UUID=ca1cb209-66f0-4d0d-a595-e85e33baf336
3、求每班總成績和平均成績。
[root@localhost ~]# cat awktest.txt name class score wang 1 100 zhang 2 90 li 1 80 a 1 55 b 2 85 c 2 74
求總成績:
[root@localhost ~]# awk '/[[:digit:]]$/{i=$3;total=total+i}END{print total}' awktest.txt 484
不同班級的成績:
[root@localhost ~]# awk '$2==1{i=$3;total=total+i}END{print total}' awktest.txt 235 [root@localhost ~]# awk '/1/{i=$3;total=total+i}END{print total}' awktest.txt 235 [root@localhost ~]# awk '/2/{i=$3;total=total+i}END{print total}' awktest.txt 249 [root@localhost ~]# awk '$2==2{i=$3;total=total+i}END{print total}' awktest.txt 249
平均成績:
[root@localhost ~]# awk '($2==2){i=$3;total=total+i}END{print total/NF}' awktest.txt 83 [root@localhost ~]# awk '($2==1){i=$3;total=total+i}END{print total/NF}' awktest.txt 78.3333
原創文章,作者:SilencePavilion,如若轉載,請注明出處:http://www.www58058.com/49228
文章對awk的工作原理和使用方法解析的很詳細,特別對awk的函數都通過示例展示了,很具有學習價值,贊一個。