Linux三劍客之awk精講(基礎與進階)
快捷跳轉目錄:
##第1章 awk基礎入門
###1.1 awk簡介要弄懂awk程式,必須熟悉瞭解這個工具的規則。本實戰筆記的目的是通過實際案例或面試題帶同學們熟練掌握awk在企業中的用法,而不是awk程式的幫助手冊。
- 一種名字怪異的語言
- 模式掃描和處理
###1.2 學完awk你可以掌握:awk不僅僅時linux系統中的一個命令,而且是一種程式語言,可以用來處理資料和生成報告(excel)。處理的資料可以是一個或多個檔案,可以是來自標準輸入,也可以通過管道獲取標準輸入,awk可以在命令列上直接編輯命令進行操作,也可以編寫成awk程式來進行更為複雜的運用。本章主要講解awk命令的運用。
- 記錄與欄位
- 模式匹配:模式與動作
- 基本的awk執行過程
- awk常用內建變數(預定義變數)
- awk陣列(工作常用)
- awk語法:迴圈,條件
- awk常用函式
- 向awk傳遞引數
- awk引用shell變數
- awk小程式及除錯思路
[root@chensiqi1 ~]# cat /etc/redhat-release
CentOS release 6.8 (Final)
[root@chensiqi1 ~]# uname -r
2.6.32-642.el6.x86_64
[root@chensiqi1 ~]# ll `which awk`
lrwxrwxrwx. 1 root root 4 Dec 23 20:25 /bin/awk -> gawk
[root@chensiqi1 ~]# awk --version
GNU Awk 3.1.7
Copyright (C) 1989, 1991-2009 Free Software Foundation.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see http://www.gnu.org/licenses/.
###1.4 awk的格式
- awk指令是由模式,動作,或者模式和動作的組合組成。
- 模式既pattern,可以類似理解成sed的模式匹配,可以由表示式組成,也可以是兩個正斜槓之間的正則表示式。比如NR==1,這就是模式,可以把他理解為一個條件。
- 動作即action,是由在大括號裡面的一條或多條語句組成,語句之間使用分號隔開。比如awk使用格式:
awk處理的內容可以來自標準輸入(<),一個或多個文字檔案或管道。
- pattern既模式,也可以理解為條件,也叫找誰,你找誰?高矮,胖瘦,男女?都是條件,既模式。
- action既動作,可以理解為幹啥,找到人之後你要做什麼。
模式和動作的詳細介紹我們放在後面部分,現在大家先對awk結構有一個瞭解。
示例1-1: 基本的模式和動作
[root@chensiqi1 ~]# awk -F ":" 'NR>=2 && NR<=6{print NR,$1}' /etc/passwd
2 bin
3 daemon
4 adm
5 lp
6 sync
命令說明:
-F 指定分隔符為冒號,相當於以“:”為菜刀,進行欄位的切割。
NR>=2 && NR<=6:這部分表示模式,是一個條件,表示取第2行到第6行。
{print NR,$1}:這部分表示動作,表示要輸出NR行號和$1第一列。
示例1-2 只有模式
[root@chensiqi1 ~]# awk -F ":" 'NR>=2&&NR<=6' /etc/passwd
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
命令說明:
-F指定分隔符為冒號
NR>=2&&NR<=6這部分是條件,表示取第2行到第6行。
但是這裡沒有動作,這裡大家需要了解如果只有條件(模式)沒有動作,awk預設輸出整行
示例1-3:只有動作
[root@chensiqi1 ~]# awk -F ":" '{print NR,$1}' /etc/passwd
1 root
2 bin
3 daemon
4 adm
5 lp
6 sync
7 shutdown
8 halt
9 mail
10 uucp
以下省略....
命令說明:
-F指定分隔符為冒號
這裡沒有條件,表示對每一行都處理
{print NR,$1}表示動作,顯示NR行號與$1第一列
這裡要理解沒有條件的時候,awk會處理每一行。
示例1-4:多個模式和動作
[root@chensiqi1 ~]# awk -F ":" 'NR==1{print NR,$1}NR==2{print NR,$NF}' /etc/passwd
1 root
2 /sbin/nologin
命令說明:
-F指定分隔符為冒號
這裡有多個條件與動作的組合
NR==1表示條件,行號(NR)等於1的條件滿足的時候,執行{print NR,$1}動作,輸出行號與第一列。
NR==2表示條件,行號(NR)等於2的條件滿足的時候,執行{print NR,$NF}動作,輸出行號與最後一列($NF)
注意:
- Pattern和{Action}需要用單引號引起來,防止shell作解釋。
- Pattern是可選的。如果不指定,awk將處理輸入檔案中的所有記錄。如果指定一個模式,awk則只處理匹配指定的模式的記錄。
- {Action}為awk命令,可以是但個命令,也可以多個命令。整個Action(包括裡面的所有命令)都必須放在{ 和 }之間。
- Action必須被{ }包裹,沒有被{ }包裹的就是Patern
- file要處理的目標檔案
在深入瞭解awk前,我們需要知道awk如何處理檔案的。
示例1-5 示例檔案的建立
[root@chensiqi1 ~]# mkdir /server/files/ -p
[root@chensiqi1 ~]# head /etc/passwd > /server/files/awkfile.txt
[root@chensiqi1 ~]# cat /server/files/awkfile.txt
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
shutdown:x:6:0:shutdown:/sbin:/sbin/shutdown
halt:x:7:0:halt:/sbin:/sbin/halt
mail:x:8:12:mail:/var/spool/mail:/sbin/nologin
uucp:x:10:14:uucp:/var/spool/uucp:/sbin/nologin
這個檔案僅包含十行檔案,我們使用下面的命令:
示例1-6 awk執行過程演示
[root@chensiqi1 ~]# awk 'NR>=2{print $0}' /server/files/awkfile.txt
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
shutdown:x:6:0:shutdown:/sbin:/sbin/shutdown
halt:x:7:0:halt:/sbin:/sbin/halt
mail:x:8:12:mail:/var/spool/mail:/sbin/nologin
uucp:x:10:14:uucp:/var/spool/uucp:/sbin/nologin
命令說明:
條件NR>=2,表示行號大於等於2時候,執行{print $0}顯示整行。
awk是通過一行一行的處理檔案,這條命令中包含模式部分(條件)和動作部分(動作),awk將處理模式(條件)指定的行
####1.6.1 小結awk執行過程
1)awk讀入第一行內容
2)判斷是否符合模式中的條件NR>=2
a,如果匹配則執行對應的動作{print $0}
b,如果不匹配條件,繼續讀取下一行
3)繼續讀取下一行
4)重複過程1-3,直到讀取到最後一行(EOF:end of file)
名稱 | 含義 |
---|---|
record | 記錄,行 |
field | 域,區域,欄位,列 |
檢視一下下面這段文字
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
shutdown:x:6:0:shutdown:/sbin:/sbin/shutdown
halt:x:7:0:halt:/sbin:/sbin/halt
mail:x:8:12:mail:/var/spool/mail:/sbin/nologin
uucp:x:10:14:uucp:/var/spool/uucp:/sbin/nologin
思考:
一共有多少行呢?你如何知道的?通過什麼標誌?
####1.7.2 記錄分隔符-RSawk對每個要處理的輸入資料認為都是具有格式和結構的,而不僅僅是一堆字串。預設情況下,每一行內容都是一條記錄,並以換行符分隔(\n)結束
- awk預設情況下每一行都是一個記錄(record)
- RS既record separator輸入輸出資料記錄分隔符,每一行是怎麼沒的,表示每個記錄輸入的時候的分隔符,既行與行之間如何分隔。
- NR既number of record 記錄(行)號,表示當前正在處理的記錄(行)的號碼。
- ORS既output record separator 輸出記錄分隔符。
awk使用內建變數RS來存放輸入記錄分隔符,RS表示的是輸入的記錄分隔符,這個值可以通過BEGIN模組重新定義修改。
示例1-1:使用“/”為預設記錄分隔符
示例檔案:
[root@chensiqi1 ~]# cat /server/files/awkfile.txt
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
shutdown:x:6:0:shutdown:/sbin:/sbin/shutdown
halt:x:7:0:halt:/sbin:/sbin/halt
mail:x:8:12:mail:/var/spool/mail:/sbin/nologin
uucp:x:10:14:uucp:/var/spool/uucp:/sbin/nologin
[root@chensiqi1 ~]# awk 'BEGIN{RS="/"}{print NR,$0}' /server/files/awkfile.txt
1 root:x:0:0:root:
2 root:
3 bin
4 bash
bin:x:1:1:bin:
5 bin:
6 sbin
7 nologin
daemon:x:2:2:daemon:
8 sbin:
9 sbin
10 nologin
adm:x:3:4:adm:
11 var
12 adm:
13 sbin
14 nologin
lp:x:4:7:lp:
15 var
16 spool
17 lpd:
18 sbin
19 nologin
sync:x:5:0:sync:
20 sbin:
21 bin
22 sync
shutdown:x:6:0:shutdown:
23 sbin:
24 sbin
25 shutdown
halt:x:7:0:halt:
26 sbin:
27 sbin
28 halt
mail:x:8:12:mail:
29 var
30 spool
31 mail:
32 sbin
33 nologin
uucp:x:10:14:uucp:
34 var
35 spool
36 uucp:
37 sbin
38 nologin
命令說明:
在每行的開始先列印輸出NR(記錄號行號),並打印出每一行$0(整行)的內容。
我們設定RS(記錄分隔符)的值為“/”,表示一行(記錄)以“/”結束
在awk眼中,檔案是從頭到尾一段連續的字串,恰巧中間有些\n(回車換行符),\n也是字元哦。
我們回顧下“行(記錄)”到底是什麼意思?
- 行(記錄):預設以\n(回車換行)結束。而這個行的結束不就是記錄分隔符嘛。
- 所以在awk中,RS(記錄分隔符)變量表示著行的結束符號(預設是回車換行)
在工作中,我們可以通過修改RS變數的值來決定行的結束標誌,最終來決定“每行”的內容。
為了方便人們理解,awk預設就把RS的值設定為“\n”
####1.7.3 對$0的認識注意:
awk的BEGIN模組,我會在後面(模式-BEGIN模組)詳細講解,此處大家僅需要知道在BEGIN模組裡面我們來定義一些awk內建變數即可。
- 如1.7.2的例子,可以看出awk中$0表示整行,其實awk使用$0來表示整條記錄。記錄分隔符存在RS變數中,或者說每個記錄以RS內建變數結束。
- 另外,awk對每一行的記錄號都有一個內建變數NR來儲存,每處理完一條記錄,NR的值就會自動+1
- 下面通過示例來加深印象。
示例1-2:NR記錄號
[root@chensiqi1 ~]# awk '{print NR,$0}' /server/files/awkfile.txt
1 root:x:0:0:root:/root:/bin/bash
2 bin:x:1:1:bin:/bin:/sbin/nologin
3 daemon:x:2:2:daemon:/sbin:/sbin/nologin
4 adm:x:3:4:adm:/var/adm:/sbin/nologin
5 lp:x:4:7:lp:/var/spool/lpd:/sbin/nologin
6 sync:x:5:0:sync:/sbin:/bin/sync
7 shutdown:x:6:0:shutdown:/sbin:/sbin/shutdown
8 halt:x:7:0:halt:/sbin:/sbin/halt
9 mail:x:8:12:mail:/var/spool/mail:/sbin/nologin
10 uucp:x:10:14:uucp:/var/spool/uucp:/sbin/nologin
命令說明:
NR既number of record,當前記錄的記錄號,剛開始學也可以理解為行號。
$0表示整行或者說整個記錄
####1.7.4 企業面試題:按單詞出現頻率降序排序(計算檔案中每個單詞的重複數量)
注:(此處使用sort與uniq即可)
題目:
題目建立方法:
sed -r '1,10s#[^a-zA-Z]+# #g' /etc/passwd>/server/files/count.txt
[root@chensiqi1 files]# cat /server/files/count.txt
root x root root bin bash
bin x bin bin sbin nologin
daemon x daemon sbin sbin nologin
adm x adm var adm sbin nologin
lp x lp var spool lpd sbin nologin
sync x sync sbin bin sync
shutdown x shutdown sbin sbin shutdown
halt x halt sbin sbin halt
mail x mail var spool mail sbin nologin
uucp x uucp var spool uucp sbin nologin
思路:
讓所有單詞排成一列,這樣每個單詞都是單獨的一行
1)設定RS值為空格
2)將檔案裡面的所有空格替換為回車換行符“\n”
3)grep所有連續的字母,grep -o引數讓他們排成一列。
方法一:
[root@chensiqi1 files]# awk 'BEGIN{RS="[ ]+"}{print $0}' count.txt | sort |uniq -c|sort
1
1 bash
1 lpd
2 daemon
2 lp
3 adm
3 halt
3 mail
3 root
3 shutdown
3 spool
3 sync
3 uucp
4 var
5 bin
6 nologin
10 x
12 sbin
方法二:
[root@chensiqi1 files]# cat count.txt | tr " " "\n" | sort | uniq -c | sort
1 bash
1 lpd
2 daemon
2 lp
3 adm
3 halt
3 mail
3 root
3 shutdown
3 spool
3 sync
3 uucp
4 var
5 bin
6 nologin
10 x
12 sbin
方法三:
[root@chensiqi1 files]# grep -o "[a-zA-Z]\+" count.txt | sort | uniq -c | sort
1 bash
1 lpd
2 daemon
2 lp
3 adm
3 halt
3 mail
3 root
3 shutdown
3 spool
3 sync
3 uucp
4 var
5 bin
6 nologin
10 x
12 sbin
####1.7.5 awk記錄知識小結- NR存放著每個記錄的號(行號)讀取新行時候會自動+1
- RS是輸入資料的記錄的分隔符,簡單理解就是可以指定每個記錄的結尾標誌。
- RS作用就是表示一個記錄的結束
- 當我們修改了RS的值,最好配合NR(行)來檢視變化,也就是修改了RS的值通過NR檢視結果,除錯awk程式。
- ORS輸出資料的記錄的分隔符
####1.7.6 欄位(列)awk學習技巧一則:
大象放冰箱分幾步?開啟冰箱,把大象放進去,關閉冰箱門。
awk也是一樣的,一步一步來,先修改了RS,然後用NR除錯,看看到底如何分隔的。然後通過sort排序,uniq -c去重
- 每條記錄都是由多個區域(field)組成的,預設情況下區域之間的分隔符是由空格(即空格或製表符)來分隔,並且將分隔符記錄在內建變數FS中,每行記錄的區域數儲存在awk的內建變數NF中。
- FS既field separator,輸入欄位(列)分隔符。分隔符就是菜刀,把一行字串切為很多個區域。
- NF既number of fileds,表示一行中列(欄位)的個數,可以理解為菜刀切過一行後,切成了多少份。
OFS輸出欄位(列)分隔符
- awk使用內建變數FS來記錄區域分隔符的內容,FS可以在命令列上通過-F引數來更改,也可以通過BEGIN模組來更改。
- 然後通過$n,n是整數,來取被切割後的區域,$1取第一個區域,$2取第二個區域,$NF取最後一個區域。
下面我們通過示例來加強學習。
示例1-3:指定分隔符
[root@chensiqi1 files]# awk -F ":" 'NR>=2&&NR<=5{print $1,$3}' /server/files/awkfile.txt
bin 1
daemon 2
adm 3
lp 4
命令說明:
以:(冒號)為分隔符,顯示第2行到第5行之間的第一區域和第三區域。
- 此處的FS知識一個字元,其實它可以指定多個的,此時FS指定的值可以是一個正則表示式。
- 正常情況下,當你指定分隔符(非空格)的時候,例如指定多個區域分隔符,每個分隔符就是一把刀,把左右兩邊切為兩個部分。
企業面試題:同時取出chensiqi和215379068這兩個內容(指定多分隔符)
[root@chensiqi1 files]# echo "I am chensiqi,my qq is 1234567890">>/server/files/chensiqi.txt
[root@chensiqi1 files]# cat /server/files/chensiqi.txt
I am chensiqi,my qq is 1234567890
同時取出chensiqi和1234567890這兩個內容。
思路:
我們用預設的想法一次使用一把刀,需要配合管道的。如何同時使用兩把刀呢?看下面的結果
[root@chensiqi1 files]# awk -F "[ ,]" '{print $3,$NF}' /server/files/chensiqi.txt
chensiqi 1234567890
命令說明:
通過命令-F引數指定區域分隔符
[ ,]是正則表示式裡面的內容,它表示一個整體,“一個”字元,既空格或者逗號(,),合併在一起,-F “[ ,]”就表示以空格或者逗號(,)為區域分隔符
小技巧:
在動作(‘{print $3,$NF}’)裡面的逗號,表示空格,其實動作中的逗號就是OFS的值,我們會在後面說明。剛開始大家把動作中的都逗號,當作空格即可。
示例:預設分隔符和指定分隔符會有些差異
[root@chensiqi1 files]# ifconfig eth0 | awk 'NR==2' >/server/files/awkblank.txt
[root@chensiqi1 files]# cat /server/files/awkblank.txt
inet addr:192.168.197.133 Bcast:192.168.197.255 Mask:255.255.255.0
#預設分隔符時候
[root@chensiqi1 files]# awk '{print $1}' /server/files/awkblank.txt
inet
#指定分隔符時候
[root@chensiqi1 files]# awk -F "[ :]+" '{print $1}' /server/files/awkblank.txt
[root@chensiqi1 files]# awk -F "[ :]+" '{print $2}' /server/files/awkblank.txt
inet
命令說明:
awk預設的FS分隔符對於空格序列,一個空格或多個空格tab都認為是一樣的,一個整體。
- 這個檔案的開頭有很多連續的空格,然後才是inet這個字元
- 當我們使用預設的分隔符的時候,$1是有內容的。
- 當我們指定其他分隔符(非空格)時候,區域會有所變化
- 到底為何會這樣,我們在這裡不再深入研究,只要瞭解有這種情況,注意一下即可。
現在說說ORS和OFS這兩個內建變數的含義。
- RS是輸入記錄分隔符,決定awk如何讀取或分隔每行(記錄)
- ORS表示輸出記錄分隔符,決定awk如何輸出一行(記錄)的,預設是回車換行(\n)
- FS是輸入區域分隔符,決定awk讀入一行後如何再分為多個區域。
- OFS表示輸出區域分隔符,決定awk輸出每個區域的時候使用什麼分隔她們。
- awk無比強大,你可以通過RS,FS決定awk如何讀取資料。你也可以通過修改ORS,OFS的值指定awk如何輸出資料。
現在你應該會對awk的記錄欄位有所瞭解了,下面我們總結一下,學會給階段性知識總結是學好運維的必備技能。
- RS記錄分隔符,表示每行的結束標誌
- NR行號(記錄號)
- FS欄位分隔符,每列的分隔標誌或結束標誌
- NF就是每行有多少列,每個記錄中欄位的數量
$符號表示取某個列(欄位),$1$2$NF
- NF表示記錄中的區域(列)數量,
$NF
取最後一個列(區域。) - FS(-F)欄位(列)分隔符,-F(FS)“:”<==>‘BEGIN{FS=':'}’
- RS 記錄分隔符(行的結束標識)
- NR 行號
- 選好合適的刀FS(***),RS,OFS,ORS
- 分隔符==>結束標識
- 記錄與區域,你就對我們所謂的行與列,有了新的認識(RS,FS)
到了這裡我們回頭看看,我們之前學習的內容。
- awk的命令列結構
- awk的模式和動作
- awk的記錄和欄位
比較核心常用的是欄位。
另外這些企業面試題可是學會awk的必備,必須自己也能寫出來。
接下來就詳細介紹下,awk的模式都有幾種:
- 正則表示式作為模式
- 比較表示式作為模式
- 範圍模式
- 特殊模式BEGIN和END
awk的模式是你玩好awk的必備也是最基礎的內容,必須熟練掌握
###2.2 正則表示式作為模式awk同sed一樣也可以通過模式匹配來對輸入的文字進行匹配處理。說到模式匹配,肯定少不了正則表示式,awk也支援大量的正則表示式模式,大部分與sed支援的元字元類似,而且正則表示式是玩轉三劍客的必備工具,下表列出了awk支援的正則表示式元字元:
awk預設就支援的元字元:
元字元 | 功能 | 示例 | 解釋 |
---|---|---|---|
^ | 字串開頭 | /chensiqi/或$3~/chensiqi/ | 匹配所有以chensiqi開頭的字串;匹配出所有第三列中以chensiqi開頭的 |
$ | 字串結尾 | /chensiqi$/或$3~/chensiqi$/ | 匹配所有以chensiqi結尾的字串;匹配第三列中以chensiqi結尾的 |
.(點) | 匹配任意但個字元(包括回車符) | /c..l/ | 匹配字母c,然後兩個任意字元,再以l結尾的行 |
* | 重複0個或多個前一個字元 | /a*cool/ | 匹配0個或多個a之後緊跟著cool的行 |
+ | 重複前一個字元一次或多次 | /a+b/ | 匹配一個或多個a加上字串b的行 |
? | 匹配0個或一個前邊的字元 | /a?b/ | 匹配以字母a或b或c開頭的行 |
[] | 匹配指定字元組內的任一個字元 | /[1]/ | 匹配以字母a或b或c開頭的行 |
[^] | 匹配不在指定字元組內的任一字元 | /[abc]/ | 匹配不以字母a或b或c開頭的行 |
() | 子表示式組合 | /(chensiqi)+/ | 表示一個或多個cool組合,當有一些字元需要組合時,使用括號括起來 |
| |
或者的意思 | /(chensiqi)|B/ |
匹配chensiqi或字母B的行 |
awk預設不支援的元字元:(引數--posix)
元字元 | 功能 | 示例 | 解釋 |
---|---|---|---|
x{m} | x字元重複m次 | /cool{5}/ | 匹配l字元5次 |
x{m,} | x字元重複至少m次 | /(cool){2,}/ | 匹配cool整體,至少2次 |
x{m,n} | x字元重複至少m次,但不超過n次 | /(cool){5,6}/ | 匹配cool整體,至少5次,最多6次 |
提示:
- 加括號代表整體匹配,不加那麼就匹配前邊的一個字元。awk預設不支援這種形式的正則,需要加--posix引數或者--re-interval
- 正則表示式的運用,預設是在行內查詢匹配的字串,若有匹配則執行action操作,但是有時候僅需要固定的列來匹配指定的正則表示式,比如:我想取/etc/passwd檔案中第五列{$5}這一列查詢匹配mail字串的行,這樣就需要用另外兩個匹配操作符,並且awk裡面只有這兩個操作符來匹配正則表示式。
awk正則匹配操作符:
~ | 用於對記錄或區域的表示式進行匹配 |
---|---|
!~ | 用於表達與~相反的意思 |
下面還是通過具體示例來看看,awk如何來通過正則表示式匹配字串的
####2.2.2 awk正則表示式匹配整行[root@chensiqi1 files]# awk -F ":" '/^root/' awkfile.txt
root:x:0:0:root:/root:/bin/bash
和下面的效果是一樣的
[root@chensiqi1 files]# awk -F ":" '$0~/^root/' awkfile.txt
root:x:0:0:root:/root:/bin/bash
提示:
awk只用正則表示式的時候是預設匹配整行的即‘$0~/root/’和‘/root/’是一樣的。
####2.2.3 awk正則表示式匹配一行中的某一列[root@chensiqi1 files]# awk -F ":" '$5~/shutdown/' awkfile.txt
shutdown:x:6:0:shutdown:/sbin:/sbin/shutdown
提示:
- $5表示第五個區域(列)
- ~表示匹配(正則表示式匹配)
- /shutdown/表示匹配shutdown這個字串
合併在一起
$5~/shutdown/表示第五個區域(列)匹配正則表示式/shutdown/,既第5列包含shutdown這個字串,則顯示這一行。
####2.2.4 某個區域中的開頭和結尾知道了如何使用正則表示式匹配操作符之後,我們來看看awk正則與grep和sed不同的地方。
awk正則表示式
^ | 匹配一個字串的開頭 |
---|---|
$ | 匹配一個字串的結尾 |
在sed和grep這兩個命令中,我們都把它們當作行的開頭和結尾。但是在awk中他表示的是字串的開頭和結尾。
接下來我們通過練習題來聯絡awk如何使用正則表示式。
####2.2.5 建立測試環境[root@chensiqi1 ~]# cat >>/server/files/reg.txt<<KOF
Zhang Dandan 41117397 :250:100:175
Zhang Xiaoyu 390320151 :155:90:201
Meng Feixue 80042789 :250:60:50
Wu Waiwai 70271111 :250:80:75
Liu Bingbing 41117483 :250:100:175
Wang Xiaoai 3515064655 :50:95:135
Zi Gege 1986787350 :250:168:200
Li Youjiu 918391635 :175:75:300
Lao Nanhai 918391635 :250:100:175
KOF
####2.2.6 測試檔案說明
Zhang Dandan 41117397 :250:100:175
Zhang Xiaoyu 390320151 :155:90:201
Meng Feixue 80042789 :250:60:50
Wu Waiwai 70271111 :250:80:75
Liu Bingbing 41117483 :250:100:175
Wang Xiaoai 3515064655 :50:95:135
Zi Gege 1986787350 :250:168:200
Li Youjiu 918391635 :175:75:300
Lao Nanhai 918391635 :250:100:175
說明:
- 第一列是姓氏
- 第二列是名字
- 第一列第二列合起來就是姓名
- 第三列是對應的ID號碼
- 最後三列是三次捐款數量
練習題1:顯示姓Zhang的人的第二次捐款金額及她的名字
練習題2:顯示Xiaoyu的名字和ID號碼
練習題3:顯示所有以41開頭的ID號碼的人的全名和ID號碼
練習題4:顯示所有以一個D或X開頭的人名全名
練習題5:顯示所有ID號碼最後一位數字是1或5的人的全名
練習題6:顯示Xiaoyu的捐款,每個值都有以$開頭。如$520$200$135
練習題7:顯示所有人的全名,以姓,名的格式顯示,如Meng,Feixue
####2.2.8 awk正則表示式練習題-詳解示例1:顯示姓Zhang的人的第二次捐款金額及她的名字
[root@chensiqi1 files]# cat reg.txt
Zhang Dandan 41117397 :250:100:175
Zhang Xiaoyu 390320151 :155:90:201
Meng Feixue 80042789 :250:60:50
Wu Waiwai 70271111 :250:80:75
Liu Bingbing 41117483 :250:100:175
Wang Xiaoai 3515064655 :50:95:135
Zi Gege 1986787350 :250:168:200
Li Youjiu 918391635 :175:75:300
Lao Nanhai 918391635 :250:100:175
[root@chensiqi1 files]# awk -F "[ :]+" '$1~/^Zhang/{print $2,$(NF-1)}' reg.txt
Zhang 100
Zhang 90
說明:
- -F指定分隔符,現在大家知道了-F即FS也是支援正則表示式的。
- 【 :】+ 表示連續的空格或冒號
- -F “【 :】+” 以連續的空格或冒號為分隔符
- /Zhang/表示條件,整行中包含Dan字元的這個條件。
- {print $1,$(NF-1)} 表示動作,滿足條件後,執行顯示第一列($1)和倒數第二列($(NF-1))當然$5也可以。
注意:
NF是一行中有多少列,NF-1整行就是倒數第二列。
$(NF-1)就是取倒數第二列內容。
示例2:顯示Xiaoyu的姓氏和ID號碼
[root@chensiqi1 files]#cat reg.txt
Zhang Dandan 41117397 :250:100:175
Zhang Xiaoyu 390320151 :155:90:201
Meng Feixue 80042789 :250:60:50
Wu Waiwai 70271111 :250:80:75
Liu Bingbing 41117483 :250:100:175
Wang Xiaoai 3515064655 :50:95:135
Zi Gege 1986787350 :250:168:200
Li Youjiu 918391635 :175:75:300
Lao Nanhai 918391635 :250:100:175
[root@chensiqi1 files]# awk -F "[ :]+" '$2~/^Xiaoyu/{print $1,$3}' reg.txt
Zhang 390320151
命令說明:
指定分隔符-F “【:】+”
$2~/Xiaoyu/表示條件,第二列包含Xiaoyu時候執行對應的動作
{print $1,$3}表示動作,顯示第一列和第三列的內容
示例3:顯示所有以41開頭的ID號碼的人的全名和ID號碼
[root@chensiqi1 files]# cat reg.txt
Zhang Dandan 41117397 :250:100:175
Zhang Xiaoyu 390320151 :155:90:201
Meng Feixue 80042789 :250:60:50
Wu Waiwai 70271111 :250:80:75
Liu Bingbing 41117483 :250:100:175
Wang Xiaoai 3515064655 :50:95:135
Zi Gege 1986787350 :250:168:200
Li Youjiu 918391635 :175:75:300
Lao Nanhai 918391635 :250:100:175
[root@chensiqi1 files]# awk -F "[ :]+" '$3~/^(41)/{print $1,$2,$3}' reg.txt
Zhang Dandan 41117397
Liu Bingbing 41117483
示例4:顯示所有以一個D或X開頭的人名全名
[root@chensiqi1 files]# cat reg.txt
Zhang Dandan 41117397 :250:100:175
Zhang Xiaoyu 390320151 :155:90:201
Meng Feixue 80042789 :250:60:50
Wu Waiwai 70271111 :250:80:75
Liu Bingbing 41117483 :250:100:175
Wang Xiaoai 3515064655 :50:95:135
Zi Gege 1986787350 :250:168:200
Li Youjiu 918391635 :175:75:300
Lao Nanhai 918391635 :250:100:175
[root@chensiqi1 files]# awk -F "[ :]+" '$2~/^D|^X/{print $1,$2}' reg.txt
Zhang Dandan
Zhang Xiaoyu
Wang Xiaoai
命令說明:
-F “【 :】+”指定分隔符
|表示或,^以...開頭
注意:
這裡要用()括號表示即(D|X)相當於D|X,有的同學寫成D|X這樣是錯誤的。
示例5:顯示所有ID號碼最後一位數字是1或5的人的全名
[root@chensiqi1 files]# cat reg.txt
Zhang Dandan 41117397 :250:100:175
Zhang Xiaoyu 390320151 :155:90:201
Meng Feixue 80042789 :250:60:50
Wu Waiwai 70271111 :250:80:75
Liu Bingbing 41117483 :250:100:175
Wang Xiaoai 3515064655 :50:95:135
Zi Gege 1986787350 :250:168:200
Li Youjiu 918391635 :175:75:300
Lao Nanhai 918391635 :250:100:175
[root@chensiqi1 files]# awk -F "[ :]+" '$3~/1$|5$/{print $1,$2}' reg.txt
Zhang Xiaoyu
Wu Waiwai
Wang Xiaoai
Li Youjiu
Lao Nanhai
示例6:顯示Xiaoyu的捐款,每個值都有以$開頭。如$520$200$135
[root@chensiqi1 files]# cat reg.txt
Zhang Dandan 41117397 :250:100:175
Zhang Xiaoyu 390320151 :155:90:201
Meng Feixue 80042789 :250:60:50
Wu Waiwai 70271111 :250:80:75
Liu Bingbing 41117483 :250:100:175
Wang Xiaoai 3515064655 :50:95:135
Zi Gege 1986787350 :250:168:200
Li Youjiu 918391635 :175:75:300
Lao Nanhai 918391635 :250:100:175
[root@chensiqi1 files]# awk -F "[ :]+" '$2~/Xiaoyu/{print "$"$4"$"$5"$"$6}' reg.txt
$155$90$201
示例7:顯示所有人的全名,以姓,名的格式顯示,如Meng,Feixue
[root@chensiqi1 files]# cat reg.txt
Zhang Dandan 41117397 :250:100:175
Zhang Xiaoyu 390320151 :155:90:201
Meng Feixue 80042789 :250:60:50
Wu Waiwai 70271111 :250:80:75
Liu Bingbing 41117483 :250:100:175
Wang Xiaoai 3515064655 :50:95:135
Zi Gege 1986787350 :250:168:200
Li Youjiu 918391635 :175:75:300
Lao Nanhai 918391635 :250:100:175
[root@chensiqi1 files]# awk -F "[ ]+" '{print $1","$2}' reg.txt
Zhang,Dandan
Zhang,Xiaoyu
Meng,Feixue
Wu,Waiwai
Liu,Bingbing
Wang,Xiaoai
Zi,Gege
Li,Youjiu
Lao,Nanhai
2.2.9 企業面試題:取出網絡卡eth0的ip地址
最簡單:hostname -I
awk處理:
方法一:
[root@chensiqi1 files]# ifconfig eth0|awk 'BEGIN{RS="[ :]"}NR==31'
192.168.197.133
方法二:
[root@chensiqi1 files]# ifconfig eth0 | awk -F "(addr:)|( Bcast:)" 'NR==2{print $2}'
192.168.197.133
方法三:
[root@chensiqi1 files]# ifconfig eth0 | awk -F "[ :]+" 'NR==2{print $4}'
192.168.197.133
方法四:
[root@chensiqi1 files]# ifconfig eth0 | awk -F "[^0-9.]+" 'NR==2{print $2}'
192.168.197.133
提示:
- 前邊的三種方法都還是比較好理解的,這第四種方法,需要學會逆向思維,看看我們要的結果10.0.0.50,ip地址:數字和點(.),我是否可以指定分隔符,以數字和點以外的字元為分隔符呢?
- 換句話說就是要排除數字和點(.)正則表示式與排除常用的就是[^0-9.]即不匹配數字和點(.)
- 最後-F “[^0-9]”位分隔符,但是要使用+,表示連續的。合起來就是:awk -F “[^0-9.]+” 'NR==2{print $2}'
####2.2.10 明明白白擴充套件正則表示式:+(加號)注意:
正則表示式是玩好awk的必要條件,必會掌握
[root@chensiqi1 files]# echo "------======1########2"
------======1########2
[root@chensiqi1 files]# echo "------======1########2" | grep "[-=#]"
------======1########2
[root@chensiqi1 files]# echo "------======1########2" | grep -o "[-=#]"
-
-
-
-
-
-
=
=
=
=
=
=
#
#
#
#
#
#
#
#
####2.2.11 awk正則之{} -花括號
awk中的花括號有些不常用,但是偶爾會用到這裡簡單介紹。
示例:取出awkfile中第一列包含一個o或者兩個o的行
[root@chensiqi1 files]# awk -F: '$1~/o{1,2}/' awkfile.txt
[root@chensiqi1 files]# awk -F: --posix '$1~/o{1,2}/' awkfile.txt
root:x:0:0:root:/root:/bin/bash
daemon:x:2:2:daemon:/sbin:/sbin/nologin
shutdown:x:6:0:shutdown:/sbin:/sbin/shutdown
[root@chensiqi1 files]# awk -F: --re-interval '$1~/o{1,2}/' awkfile.txt
root:x:0:0:root:/root:/bin/bash
daemon:x:2:2:daemon:/sbin:/sbin/nologin
shutdown:x:6:0:shutdown:/sbin:/sbin/shutdown
####2.2.12 企業案例1:取出常用服務埠號 思路: linux下面服務與埠資訊的對應表格在/etc/services裡面,所以這道題要處理/etc/services檔案。
我們簡單分析以下servics檔案:
[root@chensiqi1 ~]# sed -n '23,30p' /etc/services
tcpmux 1/tcp # TCP port service multiplexer
tcpmux 1/udp # TCP port service multiplexer
rje 5/tcp # Remote Job Entry
rje 5/udp # Remote Job Entry
echo 7/tcp
echo 7/udp
discard 9/tcp sink null
discard 9/udp sink null
從23行開始基本上每一行第一列是服務名稱,第二列的第一部分是埠號,第二列的第二部分是tcp或udp協議。
方法:
[root@chensiqi1 ~]# awk -F "[ /]+" '$1~/^(ssh)$|^(http)$|^(https)$|^(mysql)$|^(ftp)$/{print $1,$2}' /etc/services |sort|uniq
ftp 21
http 80
https 443
mysql 3306
ssh 22
提示:
- |是或者的意思,正則表示式
- sort是將輸出結果排序
- uniq是去重複但不標記重複個數
- uniq -c去重複但標記重複個數
###2.3 比較表示式做為模式-需要一些例子同學們自己嘗試下
之前我們看了正則表示式在awk下的運用,下面再具體看看比較表示式如何在awk下工作。
awk是一種程式語言,能夠進行更為複雜的判斷,當條件為真時候,awk就執行相關的action。主要是針對某一區域做出相關的判斷,比如列印成績在80分以上的行,這樣就必須對這一區域做比較判斷,下表列出了awk可以使用的關係運算符,可以用來比較數字字串,還有正則表示式。當表示式為真時候,表示式結果1,否0,只有表示式為真,awk才執行相關的action
運算子 | 含義 | 示例 |
---|---|---|
< | 小於 | x>y |
<= | 小於等於 | x<=y |
== | 等於 | x==y |
!= | 不等於 | x!=y |
>= | 大於或等於 | x>=y |
> | 大於 | x<y |
以上運算子是針對數字的,下面兩個運算子之前已有示例,針對字串
~ | 與正則表示式匹配 | x~/y/ |
---|---|---|
!~ | 與正則表示式不匹配 | x!~y |
思路:
想表示一個範圍,一個行的範圍,就要用到NR這個內建變量了,同時也要用到比較表示式。
答案:
[root@www ~]# awk 'NR>=23&&NR<=30' /etc/services
[root@www ~]# awk 'NR>22&&NR<31' /etc/services
過程:
[root@www ~]# awk 'NR>=23&&NR<=30' /etc/services
tcpmux 1/tcp # TCP port service multiplexer
tcpmux 1/udp # TCP port service multiplexer
rje 5/tcp # Remote Job Entry
rje 5/udp # Remote Job Entry
echo 7/tcp
echo 7/udp
discard 9/tcp sink null
discard 9/udp sink null
[root@www ~]# awk 'NR>22&&NR<31' /etc/services
tcpmux 1/tcp # TCP port service multiplexer
tcpmux 1/udp # TCP port service multiplexer
rje 5/tcp # Remote Job Entry
rje 5/udp # Remote Job Entry
echo 7/tcp
echo 7/udp
discard 9/tcp sink null
discard 9/udp sink null
說明:
1)比較表示式比較常用的還是表示大於等於,小於等於或者等於,根據這個例子來學習即可
2)NR表示行號,大於等於23即,NR>=23小於等於30,即NR<=30
3)合起來就是NR>=23並且NR<=30,&&表示並且,同時成立的意思。
4)換一種表示式方法就是大於22行小於31行,即NR>22&&NR<31
示例:找出/etc/passwd中第五列是root的行
測試檔案:
[root@www ~]# cat /server/files/awk_equal.txt
root:x:0:0:root:/root:/bin/bash
root:x:0:0:rootroot:/root:/bin/bash
root:x:0:0:rootrooot:/root:/bin/bash
root:x:0:0:rootrooot:/root:/bin/bash
root:x:0:0:/root:/bin/bash
答案:
awk -F":" '$5=="root"' /server/files/awk_equal.txt
awk -F":" '$5~/^root$/' /server/files/awk_equal.txt
過程:
#方法一:
[root@www ~]# awk -F":" '$5=="root"' /server/files/awk_equal.txt
root:x:0:0:root:/root:/bin/bash
#方法二:
[root@www ~]# awk -F":" '$5~/^root$/' /server/files/awk_equal.txt
root:x:0:0:root:/root:/bin/bash
我們如果想要完全匹配root這個字串,那就用$5=="root"
即可,這也是答案裡面給大家的。
方法二:
此題也可通過正則匹配來限制root的字串。$5~/^root$/
- 範圍模式簡單理解就是從哪裡來,到哪裡去。
- 匹配從條件1開始到條件2介紹的範圍
1)還記得sed使用地址範圍來處理文字內容嘛?awk的範圍模式,與sed類似,但是又有不同,awk不能直接使用行號來作為範圍起始地址,因為awk具有內建變數NR來儲存記錄號,所有需要使用NR=1,NR=5這樣來使用。
2)範圍模式處理的原則是:先匹配從第一個模式的首次出現到第二個模式的首次出現之間的內容,執行action。然後匹配從第一個模式的下一次出現到第二個模式的下一次出現,直到文字結束。如果匹配到第一個模式而沒有匹配到第二個模式,則awk處理從第一個模式開始直到文字結束全部的行。如果第一個模式不匹配,就算第二個模式匹配,awk依舊不處理任何行。
awk '/start pos/,/end pos/{print $)} passwd chensiqi'
awk '/start pos/,NR==XXX{print $0}' passwd chensiqi
範圍模式的時候,範圍條件的時候,表示式必須能匹配一行。
示例1:
[root@www files]# awk 'NR==2,NR==5{print NR,$0}' count.txt
2 bin x bin bin sbin nologin
3 daemon x daemon sbin sbin nologin
4 adm x adm var adm sbin nologin
5 lp x lp var spool lpd sbin nologin
說明:
條件是:從第二行,到第五行
動作是:顯示行號(NR)和整行($0)
合起來就是顯示第二行到第五行的行好和整行的內容
示例2:
[root@www files]# awk '/^bin/,NR==5{print NR,$0}' awkfile.txt
2 bin:x:1:1:bin:/bin:/sbin/nologin
3 daemon:x:2:2:daemon:/sbin:/sbin/nologin
4 adm:x:3:4:adm:/var/adm:/sbin/nologin
5 lp:x:4:7:lp:/var/spool/lpd:/sbin/nologin
說明:
條件是:從以bin開頭的行,到第五行
動作是:顯示行號和整行內容
合起來就是顯示從以bin開頭的行,到第五行中的行號和整行內容。
示例3:
[root@www files]# awk -F":" '$5~/^bin/,/^lp/{print NR,$0}' awkfile.txt
2 bin:x:1:1:bin:/bin:/sbin/nologin
3 daemon:x:2:2:daemon:/sbin:/sbin/nologin
4 adm:x:3:4:adm:/var/adm:/sbin/nologin
5 lp:x:4:7:lp:/var/spool/lpd:/sbin/nologin
說明:
條件:從第五列以bin開頭的行到以lp開頭的行
動作:顯示行號和正航內容
合起來:從第三列以bin開始的行到以lp開頭的行並顯示其行號和整行內容
[root@www files]# awk -F: '$5~/^bin/,$5~/^lp/{print NR,$0}' awkfile.txt
2 bin:x:1:1:bin:/bin:/sbin/nologin
3 daemon:x:2:2:daemon:/sbin:/sbin/nologin
4 adm:x:3:4:adm:/var/adm:/sbin/nologin
5 lp:x:4:7:lp:/var/spool/lpd:/sbin/nologin
說明:
條件:從第三列以bin開頭字串的行到第三列以lp開頭字串的行
動作:顯示行號和整行
- BEGIN模組再awk讀取檔案之前就執行,一般用來定義我們的內建變數(預定義變數,eg:FS,RS),可以輸出表頭(類似excel表格名稱)
- BEGIN模式之前我們有在示例中提到,自定義變數,給內容變數賦值等,都使用過。需要注意的是BEGIN模式後面要接跟一個action操作塊,包含在大括號內。awk必須在輸入檔案進行任何處理前先執行BEGIN裡的動作(action)。我們可以不要任何輸入檔案,就可以對BEGIN模組進行測試,因為awk需要先執行完BEGIN模式,才對輸入檔案做處理。BEGIN模式常常被用來修改內建變數ORS,RS,FS,OFS等值。
1)第一個作用,內建變數的定義
示例:取eth0的IP地址
答案:
[root@www files]# ifconfig eth0|awk -F "(addr:)|( Bcast:)" 'NR==2{print $2}'
192.168.197.133
[root@www files]# ifconfig eth0 | awk -F "[ :]+" 'NR==2{print $4}'
192.168.197.133
[root@www files]# ifconfig eth0 | awk -F "[^0-9.]+" 'NR==2{print $2}'
192.168.197.133
#上面的也可以寫成
[root@www files]# ifconfig eth0 | awk 'BEGIN{FS="(addr:)|( Bcast:)"} NR==2{print $2}'
192.168.197.133
[root@www files]# ifconfig eth0 | awk 'BEGIN{FS="[ :]+"}NR==2{print $4}'
192.168.197.133
[root@www files]# ifconfig eth0 | awk 'BEGIN{FS="[^0-9.]+"}NR==2{print $2}'
192.168.197.133
注意:
命令列-F本質就是修改的FS變數
2)第二個作用,在讀取檔案之前,輸出些提示性資訊(表頭)。
[root@www files]# awk -F: 'BEGIN{print "username","UID"}{print $1,$3}' awkfile.txt
username UID #這就是輸出的表頭資訊
root 0
bin 1
daemon 2
adm 3
lp 4
sync 5
shutdown 6
halt 7
mail 8
uucp 10
說明:
要在第一行輸出一些username和UID,我們應該想到BEGIN{}這個特殊的條件(模式),因為BEGIN{}在awk讀取檔案之前執行的。
所以結果是BEGIN{print "username","UID"}
,注意print命令裡面雙引號吃啥吐啥,原樣輸出。
然後我們實現了在輸出檔案內容之前輸出“username”和“UID”,下一步輸出檔案的第一列和第三列即{print $1,$3}
最後結果就是BEGIN{print "username","UID"}{print $1,$3}
3)第三個作用,使用BEGIN模組的特殊性質,進行一些測試。
[root@www files]#簡單輸出內容:
[root@www files]# awk 'BEGIN{print "hello world!"}'
hello world!
[root@www files]# #進行計算
[root@www files]# awk 'BEGIN{print 10/3}'
3.33333
[root@www files]# awk 'BEGIN{print 10/3+1}'
4.33333
[root@www files]# awk 'BEGIN{print 10/3+1/4*9}'
5.58333
[root@www files]# #和變數有關的操作
[root@www files]# awk 'BEGIN{a=1;b=2;print a,b}'
1 2
[root@www files]# awk 'BEGIN{a=1;b=2;print a,b,a+b}'
1 2 3
4)第四種用法:配合getline讀取檔案,後面awk函式處講解
####2.5.2 awk中變數的概念簡介- 直接定義,直接使用即可
- awk中字母會被認為是變數,如果真的要給一個變數賦值字母(字串),請使用雙引號
[root@chensiqi files]# awk 'BEGIN{a=abcd;print a}'
[root@chensiqi files]# awk 'BEGIN{abcd=123456;a=abcd;print a}'
123456
[root@chensiqi files]# awk 'BEGIN{a="abcd";print a}'
abcd
說明:
沒有檔案awk依舊可以處理BEGIN模式下的動作(命令)
EHD在awk讀取完所有的檔案的時候,再執行END模組,一般用來輸出一個結果(累加,陣列結果),也可以是和BEGIN模組類似的結尾標識資訊
[root@chensiqi files]# awk 'BEGIN{print "hello world!"}{print NR,$0}END{print "end of file"}' count.txt
hello world!
1 root x root root bin bash
2 bin x bin bin sbin nologin
3 daemon x daemon sbin sbin nologin
4 adm x adm var adm sbin nologin
5 lp x lp var spool lpd sbin nologin
6 sync x sync sbin bin sync
7 shutdown x shutdown sbin sbin shutdown
8 halt x halt sbin sbin halt
9 mail x mail var spool mail sbin nologin
10 uucp x uucp var spool uucp sbin nologin
end of file
與BEGIN模式相對應的END模式,格式一樣,但是END模式僅在awk處理完所有輸入行後才進行處理。
企業案例:統計/etc/servies檔案裡的空行數量
思路:
a)空行通過正則表示式來實現:^$
b)統計數量:
- grep -c
- awk
方法一:grep
[root@chensiqi files]# grep "^$" /etc/services | wc -l
16
[root@chensiqi files]# grep -c "^$" /etc/services
16
說明:
grep命令-c表示count計數統計包含^$的行一共有多少。
方法二:
[root@chensiqi files]# awk '/^$/{i++}END{print i}' /etc/services
16
提示:
使用了awk的技術功能,很常用
第一步:統計空行個數/^$/
表示條件,匹配出空行,然後執行{i++}(i++等於i=i+1)即:/^$/{i=i+1}
我們可以通過/^$/{i=i+1;print i}
來檢視awk執行過程
[root@chensiqi files]# awk '/^$/{i=i+1;print "the value of i is:"i}' /etc/services
the value of i is:1
the value of i is:2
the value of i is:3
the value of i is:4
the value of i is:5
the value of i is:6
the value of i is:7
the value of i is:8
the value of i is:9
the value of i is:10
the value of i is:11
the value of i is:12
the value of i is:13
the value of i is:14
the value of i is:15
the value of i is:16
第二步:輸出最後結果
- 但是我們只想要最後的結果16,不想要過程怎麼辦?使用END模式輸出結果
- 因為END模式的特殊性質所以很適合輸出最終結果
所以最終結果就是awk '/^$/{i=i+1}END{print "blank lines count:"i}' /etc/services
awk程式設計思想:
- 先處理,最後再END模組輸出
{print NR,$0}body
模組處理,處理完畢後END{print "end of file"}
輸出一個結果
企業面試題5:檔案count.txt,檔案內容是1到100(由seq 100生成),請計算檔案每行值加起來的結果(計算1+...+100)
思路:
檔案每一行都有且只有一個數字,所以我們要讓檔案的每行內容相加。
回顧一下上一道題我們用的是i++即i=i+1
這裡我們需要使用到第二個常用的表示式
i=i+$0
對比一下,其實只是把上邊的1換成了$0
[root@chensiqi files]# awk '{i=i+$0}END{print i}' count.txt
5050
###2.6 awk中的動作
在一個模式-動作語句中,模式決定動作什麼時候執行,有時候動作會非常簡單:一條單獨的列印或賦值語句。在有些時候,動作有可能是多條語句,語句之間用換行符或分號分開。
awk的動作中如果有兩個或兩個以上的語句,需要用分號分隔
動作部分大家理解為花括號裡面的內容即可,總體分為:
- 表示式
- 流程控制語句
- 空語句
- 陣列(以後如果有時間的話會再寫一個awk高階部分進行介紹)
- awk命令核心由模式和動作組成
- 模式就是條件,動作就是具體幹什麼
1)正則表示式:必須掌握正則,熟練
2)條件表示式:比大小,比較是否相等
3)範圍表示式:從哪裡來到哪裡去 - 注意BEGIN或END模組只能有一個。BEGIN{}BEGIN{}或者END{}END{}都是錯誤的。
awk -F 指定分隔符 ‘BRGIN{}END{}’,如下圖
#awk完整執行過程
[root@chensiqi ~]# awk -F ":" 'BEGIN{RS="/";print "hello world!"}{print NR,$0}END{print "end of file"}' /server/files/awkfile.txt
hello world!
1 root:x:0:0:root:
2 root:
3 bin
4 bash
bin:x:1:1:bin:
5 bin:
6 sbin
7 nologin
daemon:x:2:2:daemon:
8 sbin:
9 sbin
10 nologin
adm:x:3:4:adm:
11 var
12 adm:
13 sbin
14 nologin
lp:x:4:7:lp:
15 var
16 spool
17 lpd:
18 sbin
19 nologin
sync:x:5:0:sync:
20 sbin:
21 bin
22 sync
shutdown:x:6:0:shutdown:
23 sbin:
24 sbin
25 shutdown
halt:x:7:0:halt:
26 sbin:
27 sbin
28 halt
mail:x:8:12:mail:
29 var
30 spool
31 mail:
32 sbin
33 nologin
uucp:x:10:14:uucp:
34 var
35 spool
36 uucp:
37 sbin
38 nologin
end of file
說明:
我們·同時再命令列定義了分隔符和在BEGIN模式中定義了RS內建變數,在最後通過END模式輸出了結果
awk提供了陣列來存放一組相關的值。
awk是一種程式語言,肯定也支援陣列的運用,但是又不同於c語言的陣列。陣列在awk中被稱為關聯陣列,因為它的下標既可以是數字也可以是字串。下標通常被稱作key,並且與對應的陣列元素的值關聯。陣列元素的key和值都儲存在awk程式內部的一張表中,通過一定雜湊演算法來儲存,所以陣列元素都不是按順序儲存的。打印出來的順序也肯定不是按照一定的順序,但是我們可以通過管道來對所需的資料再次操作來達到自己的效果。
如圖不難發現,awk陣列就和酒店一樣。陣列的名稱就像是酒店名稱,陣列元素名稱就像酒店房間號碼,每個陣列元素裡面的內容就像是酒店房間裡面的人。
###2.10 圖片-陣列假設我們有一個酒店
酒店<===>chensiqihotel
酒店裡面有幾個房間110,119,120,114這幾個房間
酒店110房間<===>chensiqihotel[110]
酒店120房間<===>chensiqihotel[120]
酒店119房間<===>chensiqihotel[119]
酒店114房間<===>chensiqihotel[114]
酒店房間裡面入住客人
酒店110房間住著xiaoyu<===>chensiqihotel[110]="xiaoyu"
酒店119房間住著ruxue<===>chensiqihotel[119]="ruxue"
酒店120房間住著dandan<===>chensiqihotel[120]="dandan"
酒店114房間住著waiwai<===>chensiqihotel[114]="waiwai"
示例:
[root@chensiqi ~]# awk 'BEGIN{chensiqihotel[110]="xiaoyu";chensiqihotel[119]="ruxue";chensiqihotel[120]="dandan";chensiqihotel[114]="waiwai";print chensiqihotel[110],chensiqihotel[119],chensiqihotel[120],chensiqihotel[114]}'
xiaoyu ruxue dandan waiwai
[root@chensiqi ~]# awk 'BEGIN{chensiqihotel[110]="xiaoyu";chensiqihotel[119]="ruxue";chensiqihotel[120]="dandan";chensiqihotel[114]="waiwai";for(hotel in chensiqihotel)print hotel,chensiqihotel[hotel]}'
110 xiaoyu
120 dandan
114 waiwai
119 ruxue
企業面試題1:統計域名訪問次數
處理以下檔案內容,將域名取出並根據域名進行計數排序處理:(百度和sohu面試題)
http://www.etiantian.org/index.html
http://www.etiantian.org/1.html
http://post.etiantian.org/index.html
http://mp3.etiantian.org/index.html
http://www.etiantian.org/3.html
http://post.etiantian.org/2.html
思路:
1)以斜線為菜刀取出第二列(域名)
2)建立一個數組
3)把第二列(域名)作為陣列的下標
4)通過類似於i++的形式進行計數
5)統計後把結果輸出
過程演示:
第一步:檢視一下內容
[root@chensiqi ~]# awk -F "[/]+" '{print $2}' file
www.etiantian.org
www.etiantian.org
post.etiantian.org
mp3.etiantian.org
www.etiantian.org
post.etiantian.org
命令說明:
這是我們需要計數的內容
第二步:計數
[root@chensiqi ~]# awk -F "[/]+" '{i++;print $2,i}' file
www.etiantian.org 1
www.etiantian.org 2
post.etiantian.org 3
mp3.etiantian.org 4
www.etiantian.org 5
post.etiantian.org 6
命令說明:
i++:i最開始是空的,當awk讀取一行,i自身+1
第三步:用陣列替換i
[root@chensiqi ~]# awk -F "[/]+" '{h[$2]++;print $2,h["www.etiantian.org"]}' file
www.etiantian.org 1
www.etiantian.org 2
post.etiantian.org 2
mp3.etiantian.org 2
www.etiantian.org 3
post.etiantian.org 3
命令說明:
1)將i替換成h[$2];相當於我建立了一個數組h[],然後用$2作為我的房間號。但是目前房間裡是沒有東西的。也就是說h[$2]=h["www.etiantian.org"] and h["post.etiantian.org"] and h["mp3.etiantian.org"] 但是具體房間裡是沒有東西的也就是空。
2)h[$2]++就等於i++:也就是說我開始給房間里加東西;當出現同樣的東西,我就++
3)print h["www.etiantian.org"]:意思就是說我開始要輸出了。我要輸出的是房間號為“www.etiantian.org”裡面的內容。這裡面的內容最早是空的,隨著awk讀取每一行一旦出現房間號為“www.etiantian.org”的房間時,我就給房間裡的內容進行++。
4)綜上,輸出的結果中,每次出現www.etiantian.org時,h["www.etiantian.org"]就會++。因此最後的輸出數字是3
第四步:輸出最終計數結果
[root@chensiqi ~]# awk -F "[/]+" '{h[$2]++}END{for(i in h)print i,h[i]}' file
mp3.etiantian.org 1
post.etiantian.org 2
www.etiantian.org 3
[root@chensiqi ~]#
命令說明:
我們最終需要輸出的是去重複以後的統計結果,所以得在END模組裡進行輸出
for(i in h)遍歷這個陣列,i裡存的都是房間號
print i,h[i]:輸出每一個房間號及其房間裡的內容(計數結果)
提示:
awk的應用裡最重要的一個功能就是計數,而陣列在awk裡最大的作用就是去重複。請同學們仔細理解,多動手試驗一下。
轉載:https://www.cnblogs.com/chensiqiqi/p/6481647.html
TRANSLATE with x English TRANSLATE with EMBED THE SNIPPET BELOW IN YOUR SITE Enable collaborative features and customize widget: Bing Webmaster Portal Back 帶著疑問去思考,然後串聯,進而歸納總結,不斷追問自己,進行自我辯證,像偵查嫌疑案件一樣看待技術問題,漆黑的街道,你我一起尋找線索,你就是技術界大偵探福爾摩斯