本文轉自:http://blog.csdn.net/SeeTheWorld518/article/details/48630271
awk :適用程序,一種unix工具
就是一個強大的文本分析工具,相對於grep查找、sed的編輯,awk在對數據分析並生成報告的時候,顯得尤爲強大。簡單來說awk就是把文件逐行的讀入,以空格爲默認分隔符將每行切片,切開的部分再進行各種處理。
- awk是用來操作數據和產生報表的一種編程語言。數據可能來自標準輸入、一個或多個文件或一個進程的輸出等。awk可以用在命令行裏進行簡單操作,也可應用到較大的應用程序中。
- awk是一門編程語法,作爲unix工具來使用簡化了很多,但是仍然有許多編程語言的特性,可以對目標進行一系列的處理。
-
如果拋出awk的BEGIN和END,對文件的每行,awk都分兩個階段處理:
1、讀取該行內容,分配臨時寄存器,分配域名等操作;
2、對域做各種處理並輸出; -
awk基本用途
1、簡單輸出,如 awk ‘{print 1,NF}’ — print的規則
2、作爲分隔符使用
單字符分隔符:打印系統中用戶名和其他使用shell類型
單字符分隔符,管道連續使用awk:打印nginx日誌中的訪問目錄。
多字符分隔符:抓取apache詳細版本
多字符多個分隔符:截取ip地址
正則分隔符:截取ip地址
[root@admin test]# ls -l
total 16
-rw-r--r--. 1 root root 0 Jun 15 11:03 aa.jpg
-rw-r--r--. 1 root root 12 Jun 15 10:48 ls.jpg
-rw-r--r--. 1 root root 200 Jun 15 11:31 result.jpg
-rw-r--r--. 1 root root 0 Jun 15 11:04 right.jpg
drwxr-xr-x. 2 root root 4096 Jun 20 06:39 sd.ex
-rw-r--r--. 1 root root 49 Jun 15 11:04 wrong.jpg
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
通過awk打印出第一列:
[root@admin test]# ls -l | awk '{print $1}'
total
-rw-r--r--.
-rw-r--r--.
-rw-r--r--.
-rw-r--r--.
drwxr-xr-x.
-rw-r--r--.
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
打印前兩列,也就是前兩個域:
[root@admin test]# ls -l | awk '{print $1,$2}'
total 16
-rw-r--r--. 1
-rw-r--r--. 1
-rw-r--r--. 1
-rw-r--r--. 1
drwxr-xr-x. 2
-rw-r--r--. 1
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
在awk中,拋開BEGIN和END不看,’{}’ 這是一個固定寫法。
$ : 符號表示域,域之間通過默認的分隔符 空格 分開,如果有多個空格就會變成一個空格,第一個域爲$1,第二個爲$2等…
打印最後一列:
[root@admin test]# ls -l | awk '{print $NF}'
16
aa.jpg
ls.jpg
result.jpg
right.jpg
sd.ex
wrong.jpg
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
$NF : 就代表最後一列的意思。
如果想打印倒數第二列,則使用$(NF -1)。
[root@admin test]# ls -l | awk '{print $(NF - 1)}'
total
11:03
10:48
11:31
11:04
06:39
11:04
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
-F :參數-F是改變awk的默認分隔符,可以支持正則表達式。
[root@admin test]# ls -l
total 16
-rw-r--r--. 1 root root 0 Jun 15 11:03 aa.jpg
-rw-r--r--. 1 root root 12 Jun 15 10:48 ls.jpg
-rw-r--r--. 1 root root 200 Jun 15 11:31 result.jpg
-rw-r--r--. 1 root root 0 Jun 15 11:04 right.jpg
drwxr-xr-x. 2 root root 4096 Jun 20 06:39 sd.ex
-rw-r--r--. 1 root root 49 Jun 15 11:04 wrong.jpg
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
awk默認的分隔符是 空格,空格前一列就是$1,後面是$2,$3…..
當我們改變默認分隔符爲 分號 “:”時,打印一下結果:
[root@admin test]# ls -l | awk -F":" '{print $NF}'
total 16
03 aa.jpg
48 ls.jpg
31 result.jpg
04 right.jpg
39 sd.ex
04 wrong.jpg
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
通過-F 參數改變默認分隔符,以及其支持正則表達式的特性,精確的抽出ifconfig 文件中的ip地址。
#精確的抽取ip地址
[root@admin test]# ifconfig | grep "inet addr" | awk -F "addr:| *" '{print $4}'
192.168.1.6
127.0.0.1
- 1
- 2
- 3
- 4
- 5
- 1
- 2
- 3
- 4
- 5
分析:
grep "inet addr" 表示先抽取出含有ip的那行,然後通過管道交給awk去處理
-F "addr:| *" :表示該變默認分隔符爲addr:或者連續多個空格
$4 :表示改變默認分隔符以後,ip地址在第4個域。
- 1
- 2
- 3
- 4
- 5
- 1
- 2
- 3
- 4
- 5
用grep實現抽取ip :
[root@admin home]# ifconfig | egrep -o "[0-9][0-9]*\.[0-9][0-9]*\.[0-9][0-9]*\.[0-9][0-9]*"
192.168.1.6
192.168.1.255
255.255.255.0
127.0.0.1
255.0.0.0
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 1
- 2
- 3
- 4
- 5
- 6
- 7
然後在用head和tail抽取想要的ip即可。
使用sed實現抽取ip
[root@admin home]# ifconfig |grep "inet addr" | sed 's/inet addr://' | sed 's/Bcast.*//' | head -1
192.168.1.6
或者:
[root@admin home]# ifconfig |grep "inet addr" | sed 's/^.*addr://;s/ *.*//' | head -1
192.168.1.6
- 1
- 2
- 3
- 4
- 5
- 6
- 1
- 2
- 3
- 4
- 5
- 6
awk匹配打印
注:需要匹配的內容是寫在{}外面的,通過//來體現匹配。
匹配打印實際上是文件每行讀取的時候做的處理。
1、整行中匹配內容
awk '/sth/{print $1}' ---打印匹配sth的行的第一個域,這是對整行進行操作
awk '!/sth/{print $1}' ---打印不匹配sth的行的第一個域
- 1
- 2
- 3
- 1
- 2
- 3
如匹配打印sd關鍵字:
[root@admin test]# ls
aa.jpg ls.jpg result.jpg right.jpg sd.ex wrong.jpg
[root@admin test]# ls | awk '/sd/{print $1}'
sd.ex
- 1
- 2
- 3
- 4
- 5
- 6
- 1
- 2
- 3
- 4
- 5
- 6
2、域匹配內容
匹配某個文件中以默認分隔符分隔的$1域中含有關鍵字sth的行,然後打印出第一個域,命令如下:
awk '$1~/sth/{print $1}'
- 1
- 1
3、改變awk中的默認分隔符
如打印出passwd文件中,以冒號 : 分隔的第一個域中含有關鍵字wcx行的第一個域:
[root@admin etc]# cat passwd | awk -F":" '$1~/wcx/{print $1}'
wcx
- 1
- 2
- 3
- 1
- 2
- 3
awk判斷打印
判斷打印實際上是文件每行讀取後做的處理。
格式例如:
awk '{if($1=="wcx")print $1}'
- 1
- 1
if 判斷必須是進入某一行以後才能做的,所以必須是在花括號{} 裏面。而模式匹配是先匹配到內容的行才能進行下一步操作,所以模式匹配實在花括號{}外邊。
[root@admin etc]# cat ./passwd | awk -F ":" '{if($1 == "wcx")print}
wcx:x:501:501::/home/wcx:/bin/bash
- 1
- 2
- 3
- 1
- 2
- 3
上面命令中,如果passwd文件中,以冒號分隔的第一個域==”wcx”,那麼就打印出來,這是等於判斷,所以只有wcx的行能出來。
BEGIN和END
在Unix awk中兩個特別的表達式,BEGIN和END,這兩者都可用於pattern中(參考前面的awk語法),提供BEGIN和END的作用是給程序賦予初始狀態和在程序結束之後執行一些掃尾的工作。
任何在BEGIN之後列出的操作(在{}內)將在Unix awk開始掃描輸入之前執行,而END之後列出的操作將在掃描完全部的輸入之後執行。因此,通常使用BEGIN來顯示變量和預置(初始化)變量,使用END來輸出最終結果。
awk的數組
有一個awk.txt文件,其內容如下:
[root@admin home]# cat awk.txt
kk kekea
jj d32
jame 23
sr
sr
kk
jame
wcx
jame
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
統計一下awk.txt文件中每個人名出現的次數:
[root@admin home]# cat awk.txt | awk '{a[$1]++}END{for (i in a)print i,a[i]}'
wcx 1
jj 1
kk 2
sr 2
jame 3
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 1
- 2
- 3
- 4
- 5
- 6
- 7
解題思路分析:
{a[$1]++} :awk開始掃描管道傳過來的內容,但是麼有存儲功能,現在我們需要計算每個人名出現的額次數,所以需要把掃描到的相同的人名分別存儲起來,這時候就必須用數組,並且這裏的數組都是hash數組,就是鍵值對的數組,這裏的鍵—對應的就是對應域中的人名,如kk,值 — 對應的就是kk這個人名出現的次數。數組a中的下標$1代表的是第一個域中列名,如wcx。awk開始逐行掃描,每掃到一個相同的人名,對應的hash數組裏的值就+1,如a[kk]++,直到掃到文件的結尾。(注:數組的默認值爲空,如果要做++操作了,就會把裏的值變成0)
END : END之後列出的操作將在Unix awk開始掃描完全部的輸入之後執行。上面掃描完以後,就開始執行END後面的操作了。
{for (i in a)print i,a[i]} :利用for循環去遍歷剛剛產生的hash數組,然後打印出數組下標所代表的值,也就是人名以及對數組中的值,也就是對應人名出現的次數。這裏的i,就代表數組的下標,也就是域中的人名,如kk。
awk輸出分隔符
awk默認的輸出分隔符也是空格,如果想改變默認輸出分隔符怎麼做?
[root@admin home]# cat awk.txt | awk '{print $1,$2}'
kk kekea
jj d32
jame 23
sr 234
sr edr
kk 23
jame rt
wcx 88
jame 34
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
運行結果看出,打印時,$1和$2間加了逗號以後,輸出的文本中域間就都是用空格隔開的。
如果我不加逗號,改爲加一串別的字符時,輸出後就以加入的字符作爲分隔符了。如:
[root@admin home]# cat awk.txt | awk '{print $1"--"$2"BB"}'
kk--kekeaBB
jj--d32BB
jame--23BB
sr--234BB
sr--edrBB
kk--23BB
jame--rtBB
wcx--88BB
jame--34BB
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
通過awk批量修改擴展名
[root@admin test]# ls
aa.jpg ls.jpg result.jpg right.jpg wrong.jpg
- 1
- 2
- 3
- 1
- 2
- 3
將test目錄下的以.jpg結尾的文件改成.txt結尾的文件:
[root@admin test]# ls | awk -F "." '{print "mv "$1"."$2" "$1".txt"}'|sh
[root@admin test]# ls
aa.txt ls.txt result.txt right.txt wrong.txt
或者:
[root@admin test]# ls | awk -F "." '{print "mv "$0" "$1".txt"}' | sh
#$0表示整行的內容
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
思路分析,同樣改名也是需要構造mv a.txt a.jpg這樣類似的語句的,這就用到了上面講的輸出時修改默認分隔符的操作了。構造出的mv語句再傳給sh去執行就可以實現改名的操作。