linux三劍客-------AWK

AWK是一種優良的文本處理工具,能夠格式化文本輸出,同時它自己也擁有本身的語言。AWK 提供了極其強大的功能:能夠進行樣式裝入、 流控制、數學 運算符、進程 控制語句甚至於內置的 變量和函數。它具有了一個完整的語言所應具備的幾乎全部精美特性。接下來,咱們一塊兒來認識一下這個強大的語言吧!git

1、awk基本介紹shell

  • 基本格式:awk [options] 'program' file…
[root@blwsy ~]#awk –F: '{print}' /etc/passwd

* program一般是被放在單引號或雙括號中express

* pattern和action:pattern部分決定動做語句什麼時候觸發及觸發事件 BEGIN,END ;action statements對數據進行處理,放在{}內指明 print, printf apache

  • 分割符、域和記錄

* awk執行時,由分隔符分隔的字段(域)標記$1,$2..$n稱爲域標識 。$0爲全部域,注意:和shell中變量$符含義不一樣 vim

* 文件的每一行稱爲記錄數組

* 省略action,則默認執行 print $0 的操做bash

  • 基本用法

awk     [options]  'BEGIN{ action;… } pattern{ action;… } END{ action;… }' file …
app

[root@blwsy ~]#awk –F:   '{print $1,$3,$7}’ /etc/passwd

* optiondom

-F 指明輸入時用到的字段分隔符,不指定分割符是默認空格。ssh

-v var=value: 自定義變量

awk -v FS=':'  ==  awk  -F:

* action

print格式:  print item1, item2, ...

逗號分隔符

各item形式不限,能夠字符串,也能夠數值,字段或者變量以及awk表達式

如省略item,至關於print $0 ;$0至關於打印文檔自身

2、awk變量

*   內置變量
FS:輸入字段分隔符

[root@blwsy ~]#awk -v FS=':' '{print $1,$3}' test.txt
apache              48 saslauth 498 postfix 89 gdm 42 pulse 497 sshd 74 tcpdump 72 francis 500 setroubleshoot 496 wsy 501

OFS:輸出字段分隔符

[root@blwsy ~]#awk -v FS=':' -v OFS=':' '{print $1,$3}' test.txt
apache:48 saslauth:498 postfix:89 gdm:42 pulse:497 sshd:74 tcpdump:72 francis:500 setroubleshoot:496 wsy:501

RS:輸入的記錄分隔符

[root@blwsy ~]#awk -v FS="." -v RS=" " '{print $1}' f1(一個文件)
a bbb dswwesdds e3dew4cfv

ORS:輸出的記錄分隔符

[root@blwsy ~]#awk -v FS="." -v RS=" " -v ORS="#" '{print $1}' f1
a bbb dswwesdds#2133#dasfe#wd699#

 NF:字段的數量

[root@blwsy ~]#awk '{print NF}' /etc/fstab
0
6
6
6
6

 NR:記錄號

[root@blwsy ~]#awk '{print NR,$0}' /etc/fstab 
1 
2 UUID=929873ac-4dca-40d2-9eeb-a755dbe56096 /boot     ext4   defaults    0  1
3 UUID=45c729d6-2bde-4e25-b6e0-3396cc45787c   /  ext4    defaults  0  2
4 UUID=4acb218c-f541-44aa-a3e0-d491f336a609 /app       ext4  defaults 0   0
5 UUID=646ae8f4-0f05-4feb-aa7d-0fd8906fc8ce swap   swap    defaults   0   0

 FNR:各文件分別計數,行號

[root@blwsy ~]#awk '{print FNR}' /etc/fstab /etc/inittab 兩個文件分別記錄行號
1
2
3
4
5
1
2
3
4
5 …. 16

FILENAME:當前文件名

[root@blwsy ~]#awk '{print FILENAME}' /etc/fstab
/etc/fstab /etc/fstab /etc/fstab /etc/fstab /etc/fstab

ARGC:命令行參數的個數

[root@blwsy ~]#awk '{print ARGC}' /etc/fstab /etc/shadow (參數個數爲三,awk也算)

ARGV:數組,保存的是命令行所給定的各參數

[root@blwsy ~]#awk 'BEGIN {print ARGV[2]}' /etc/fstab /etc/inittab 
/etc/inittab

打印命令行的最後一個參數

[root@blwsy ~]#awk 'BEGIN {print ARGV[ARGC-1]}' /etc/fstab /etc/inittab /etc/haha hi hello
hello

自定義變量

(1) -v var=value

(2) 在program中直接定義

[root@blwsy ~]#awk -v test="hello awk" '{print test}' /etc/fstab 
hello awk hello awk hello awk hello awk hello awk [root@blwsy ~]#awk '{sex="male";print sex}' /etc/fstab
male male male male male [root@blwsy ~]#awk '{sex="male";print sex,age;age=20}'
male male 20 male 20 male 20 male 20
  • printf命令(格式化輸出)

* 格式化輸出:printf 「FORMAT」, item1, item2, ...

(1) 必須指定FORMAT

(2) 不會自動換行,須要顯式給出換行控制符,\n

(3) FORMAT中須要分別爲後面每一個item指定格式符

* 格式符:與item一一對應

%c: 顯示字符的ASCII碼

%d, %i: 顯示十進制整數

[root@blwsy ~]#awk -F: '{printf "%-20s %10d\n",$1,$3}' /etc/passwd

%e, %E:顯示科學計數法數值

%f:顯示爲浮點數

[root@blwsy ~]#awk 'BEGIN{printf "%.2f\n",1.5*4}'

%g, %G:以科學計數法或浮點形式顯示數值

%s:顯示字符串

[root@blwsy ~]# awk -F: 'printf "%s",$1}’'etc/passwd 

%u:無符號整數

[root@blwsy ~]#awk 'BEGIN{printf "%u\n",1.5*4}'
6

%%: 顯示%自身

[root@blwsy ~]#awk 'BEGIN{printf "%s%\n",1.5*4}'
6%

*  修飾符:

#[.#]:第一個數字控制顯示的寬度;第二個#表示小數點後精度,%3.1f

-: 左對齊(默認右對齊) %-15s

+:顯示數值的正負符號 %+d

[root@blwsy ~]#df |awk -v FS=% '$0 ~ "/dev/sd" {print $1}' |awk '$NF>=10 {printf "DevName:%-10s Used:%s%%\n",$1,$5}'
DevName:/dev/sda2  Used:68% DevName:/dev/sda1  Used:38%
  • 操做符

*模式匹配符:~:左邊是否和右邊匹配包含!~:是否不匹配

[root@blwsy ~]#awk '$0 ~ "^root" {print $0}' /etc/passwd
root:x:0:0:root:/root:/bin/bash

*邏輯操做符:與&&,或||,非!

[root@blwsy ~]# awk -F: '$3==0 || $3>=1000 {print $1}' /etc/passwd 
root nfsnobody

*三目表達式 

selector?if-true-expression:if-false-expression

[root@blwsy ~]#awk -F: '{$3>=1000?usertype="Common User":usertype="Sysadmin ";printf "%15s:%s\n",$1,usertype}' /etc/passwd

*關係表達式

爲非0時,即爲真,才處理
爲0或爲空時,不處理

[root@blwsy ~]# awk -F: 'i=1;j=1{print i,j}' /etc/passwd (i=1時沒有指定動做默認輸$0,j=1時輸出i ,j

*行範圍

[root@blwsy ~]#awk -F: ‘(NR>=10&&NR<=20){print NR,$1}' /etc/passwd

BEGIN/END模式

[root@blwsy ~]#awk -F: 'BEGIN{print " USER UID \n--------------- "}{print $1,$3}END{print "=============="}' test.txt
 USER UID --------------- apache 48 saslauth 498 postfix 89 gdm 42 pulse 497 sshd 74 tcpdump 72 francis 500 setroubleshoot 496 wsy 501
==============
  • awk控制語句

*  if-else   對awk取得的整行或某個字段作條件判斷

語法:if(condition){statement;…}[else statement]

             if(condition1){statement1}else if(condition2){statement2} else{statement3}

[root@blwsy ~]#echo {1..10} |awk '{n=1;while(n<=NF){if($n%2==0){print $n,"奇數"}else {print $n,"偶數"};n++}}'
1 偶數 2 奇數 3 偶數 4 奇數 5 偶數 6 奇數 7 偶數 8 奇數 9 偶數 10 奇數

 *  while循環   對一行內的多個字段逐一相似處理時使用 對數組中的各元素逐一處理時使用

語法:while(condition){statement;…}

條件「真」,進入循環;條件「假」,退出循環

[root@blwsy ~]#cat /boot/grub/grub.conf |awk '/^[[:space:]]*kernel/{i=1;while(i<=NF){print $i,length($i);i++}}'
kernel 6
/vmlinuz-2.6.32-696.el6.x86_64 30 ro 2 root=UUID=45c729d6-2bde-4e25-b6e0-3396cc45787c 46 rhgb 4 crashkernel=auto 16 LANG=zh_CN.UTF-8 16 KEYTABLE=us 11

*  do-while循環

語法:do {statement;…}while(condition)

意義:不管真假,至少執行一次循環體

[root@blwsy ~]#awk 'BEGIN{ total=0;i=0;do{ total+=i;i++;}while(i<=100);{print total}}'
5050

*  for循環

語法:for(expr1;expr2;expr3) {statement;…}

[root@blwsy ~]#cat /boot/grub/grub.conf |awk '/^[[:space:]]*kernel/{for(i=1;i<=NF;i++){print $i,length($i)}}'
kernel 6
/vmlinuz-2.6.32-696.el6.x86_64 30 ro 2 root=UUID=45c729d6-2bde-4e25-b6e0-3396cc45787c 46 rhgb 4 crashkernel=auto 16 LANG=zh_CN.UTF-8 16 KEYTABLE=us 11

* continue 和break

continue 結束本次循環,繼續執行下次循環

break 結束這次循環,後邊可加數字表示跳出幾層循環

計算1到100 全部偶數之和

[root@blwsy ~]#awk 'BEGIN{sum=0;for(i=1;i<=100;i++){if(i%2==1)continue;sum+=i};print sum}'
2550

 

*next

提早結束對本行處理而直接進入下一行處理(awk自身循環)

[root@blwsy ~]#awk -v FS=: '{if($3%2!=0) next;print $1,$3}' /etc/passwd
  • awk數組

關聯數組:array[index-expression]

* index-expression:

   (1) 可以使用任意字符串;字符串要使用雙引號括起來

   (2) 若是某數組元素事先不存在,在引用時,awk會自動建立此元素,並將其值初始化爲「空串」

* 若要判斷數組中是否存在某元素,要使用「index in array」格式進行遍歷

計算etc/passwd中,shell腳本的類型及個數

[root@localhost ~]# awk -F: '{line[$7]++}END{for(i in line){print i,line[i]}}' /etc/passwd
/sbin/shutdown 1
/bin/bash 1
/sbin/nologin 29
/sbin/halt 1
/bin/sync 1
  • 函數

*數值處理:

          rand():返回0和1之間一個隨機數

[root@localhost ~]# awk 'BEGIN{srand();print int(rand()*100) }' srand()函數要和rand()函數一塊兒使用
84  

*字符串處理:

length([s]):返回指定字符串的長度

[root@localhost ~]# awk 'BEGIN{print length("hello")}'
5

• sub(r,s,[t]):對t字符串進行搜索r表示的模式匹配的內容,並將第一個匹配的內容替換爲s

[root@localhost ~]#echo "2008:08:08 08:08:08" | awk 'sub(/:/,「-",$1)' 
2008-08:08 08:08:08

• gsub(r,s,[t]):對t字符串進行搜索r表示的模式匹配的內容,並所有替換爲s所表示的內容

[root@localhost ~]#echo "2008:08:08 08:08:08" | awk ‘gsub(/:/,「-",$0)' 
2008-08-08 08-08-08

• split(s,array,[r]):以r爲分隔符,切割字符串s,並將切割後的結果保存至array所表示的數組 中,第一個索引值爲1,第二個索引值爲2,…

[root@localhost ~]# netstat -tan |awk '/^tcp\>/ && !($5 ~ "*"){split($5,ip,":");count[ip[1]]++}END{for(i in count){print i,count[i]}}'
172.18.250.203 2
  • 自定義函數

 格式: function name ( parameter, parameter,  ... ) { statements return expression }

  自定義一個比較大小的awk函數

[root@localhost ~]#vim fun.awk
function max(a,b){ if (a>b) var=a else var=b return var } BEGIN{a=5;b=8;print max(a,b)} [root@localhost ~]# awk -f fun.awk
8

*awk中調用shell命令

 

用 system命令進行函數調用

空格是awk中的字符串鏈接符,若是system中須要使用awk中的變量可使用空格分隔,或者說除了 awk的變量外其餘一概用""引用起來。

[root@localhost ~]#awk BEGIN'{system("hostname") }'
localhost.localdomain [root@localhost ~]#awk 'BEGIN{score=100; system("echo your score is " score) }'
your score is 100

*awk腳本

將awk程序寫成腳本,直接調用或執行

[root@localhost ~]# cat fun.awk #!/bin/awk -f
BEGIN{FS=":"} {if($3>=1000)print $1,$3} [root@localhost ~]#chmod +x fun.awk
[root@localhost ~]#./fun.awk /etc/passwd
nfsnobody 65534

 實例

一、統計/etc/fstab文件中每一個文件系統類型出現的次數

[root@localhost ~]# cat /etc/fstab |awk '!($0 ~ "#"){print $0}'|awk '{line[$3]++}END{for(i in line){print i,line[i]}}'
  3 devpts 1 swap 1 sysfs 1 proc 1 tmpfs 1 ext4 3

 

二、統計/etc/fstab文件中每一個單詞出現的次數

[root@localhost ~]# awk '{for(i=1;i<=NF;i=i+1){print $i}}' /etc/fstab |sort|uniq -c|sort -nr|awk '{printf("%s %s\n",$2,$1)}'

三、提取出字符串Yd$C@M05MB%9&Bdh7dq+YVixp3vpw中的全部數字

[root@localhost ~]# echo "Yd$C@M05MB%9&Bdh7dq+YVixp3vpw"|awk 'gsub(/[^[:digit:]]/," ")'
     05   9    7        3
相關文章
相關標籤/搜索