文本處理三劍客之awk

一、知識整理

1、awk報告生成器,格式化文本輸出

發明人:a.k.a. Aho,Kernighan,weinberger

awk程序通常由:BEGIN語句塊、能夠使用模式匹配的通用語句塊、END語句塊三部分組成。program通常是放在單引號或雙引號中。

基本用法:awk [] program var=value fiel…

program:pattern{action statements;…}

    patternaction: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

+ 顯示數值的正負符號 %+d0也會添加正號

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}

breakcontinue;退出循環和退出本次循環執行下一次循環。

[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 nameparameterparameter,{

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

(0)
SilencePavilionSilencePavilion
上一篇 2016-09-26
下一篇 2016-09-26

相關推薦

  • N26-第四周

    1、復制/etc/skel目錄為/home/tuser1,要求/home/tuser1及其內部文件的屬組和其它用戶均沒有任何訪問權限。   2.編輯/etc/group文件,添加組hadoop。          3.手動編輯/etc/passwd文件新增一行,添加用戶hadoop,其基本組ID為h…

    2017-02-22
  • Linux系統啟動過程及其修復過程簡析

    Linux組成 Linux: kernel+rootfs     kernel: 進程管理、內存管理、網絡管理、驅動程序、文件系統、安全功能     rootfs:程序和glibc     庫:函數集合, function, 調用接口(頭文…

    Linux干貨 2016-09-19
  • 內核編譯流程和自動化安裝

    內核編譯         在特定的情況我們機器上面有些硬件特性需要利用起來,但是我們現成的這個內核沒有開啟這個功能,那就需要重新編譯,把這個功能模塊加進來,或者打到vmlinux中的核心文件里面。比如ntfs功能,默認系統沒有啟用此功能,但是系統是帶這個功能的,編譯的時候時候可以…

    Linux干貨 2016-09-18
  • 磁盤分區管理之磁盤基礎知識1

    1、磁盤基礎知識 1.1 磁頭 磁頭是利用氣流漂浮在盤片上,并沒有接觸到盤片,因而可以在各軌間高速來回移動,但如果磁頭距離盤片太高,讀取的信號就會太弱;太低又會磨到盤片表面,所以盤片表面必須相當光滑平整,任何異物和塵埃均會使得磁頭摩擦到表面而造成數據永久性損壞。 硬盤讀寫磁頭為了能在磁盤表面高速來回移動讀取數據,則需漂浮在磁盤表面上,但是不能接觸,接觸就會造…

    Linux干貨 2016-09-07
  • HSRP vs VRRP

    HSRP:(Hot Standby Router Protocol)-熱備份路由協議 是cisco平臺一種特有的技術,是cisco的私有協議。 VRRP:(Virtual Router Redundancy Protocol)-虛擬路由冗余協議 是國際標準,由IETF提出的解決局域網中配置靜態網關出現單點失效現象的路由協議。 ----------------…

    Linux干貨 2016-10-19
  • Zabbix介紹、安裝配置

    Zabbix介紹、安裝配置 我們為什么需要監控? 常用的開源監控系統有哪些? Zabbix架構 Zabbix的安裝和配置 總結 前言 本篇文章轉自我的個人博客 http://anyisalin.com 歡迎大家訪問 我們為什么需要監控? 沒有監控就將系統上線, 就是在耍流氓; 在生產環境中, 監控是必不可少的, 因為我們需要實時了解業務的…

    2016-05-13

評論列表(1條)

  • 馬哥教育
    馬哥教育 2016-09-26 13:33

    文章對awk的工作原理和使用方法解析的很詳細,特別對awk的函數都通過示例展示了,很具有學習價值,贊一個。

欧美性久久久久