三劍客之-awk
目錄
1.4.2、按單詞出現頻率降序排序(計算檔案中每個單詞的重複數量)
2.6.1、第二個作用,在讀取檔案之前輸出寫提示性資訊,表頭
2.6.2、第三種用法,使用BEGIN模組的特殊性質進行測試
2.6.5、統計/etc/services檔案裡面的空行數量
一、awk簡介與使用
1.1、awk講解
awk是一種程式語言,用於在linux/unix下對文字和資料進行處理,能夠對文字進行復雜的格式處理,是一種處理文字的語言,可以進行樣式裝入、流控制、數學運算、流程控制,還有內建的變數和函式,具備一個完整語言所應具有的幾乎所有完美特性,相當於一個小型程式語言。其名稱得自於它的創始人 Alfred Aho 、Peter Weinberger 和 Brian Kernighan 姓氏的首個字母。
1.1、檢視awk版本
[root@RedHat8-2 ~]# cat /etc/redhat-release Red Hat Enterprise Linux release 8.2 (Ootpa) [root@RedHat8-2 ~]# awk --version GNU Awk 4.2.1, API: 2.0 (GNU MPFR 3.1.6-p2, GNU MP 6.1.2) Copyright (C) 1989, 1991-2018 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.2、awk的格式
awk指令是由模式,動作,或者模式和動作的組合組成,
模式即pattern,可以類似理解成sed的模式匹配,可以有表示式組成,也可以是兩個正斜槓之間的正則表示式。比如NR==1,這就是模式,可以把它理解為一個條件。
動作即action,是由在大括號裡面的一條或多條語句組成,語句之間使用分號隔開。如下awk使用格式:
awk處理的內容可以來自標準輸入(<)一個或多個文字檔案或管道
[root@RedHat8-2 ~]# awk -F ":" 'NR<=5{print $1,$3}' /etc/passwd
root 0
bin 1
daemon 2
adm 3
lp 4
####
[root@RedHat8-2 ~]# awk 引數 '條件(找誰){動作(做什麼)}' /etc/passwd
pattern即模式,可以理解為條件,以什麼條件為例去找?都是條件即模式
action即動作,可以理解為幹啥,找到之後要做什麼。
1.3、awk執行過程
1.4、記錄和欄位
下面是兩個新概念的記錄和欄位,為了方便理解可以把記錄就當做行即記錄==行,欄位相當於列,欄位==列。
名稱 |
含義 |
record |
記錄,行 |
field |
域,區域,欄位,列 |
建立測試環境:
[root@RedHat8-2 ~]# mkdir /root/test
[root@RedHat8-2 ~]# cd test
[root@RedHat8-2 test]# head /etc/passwd > /root/test/awkfile.txt
1.4.1、記錄(行)
awk對每個要處理的輸入資料認為都是具有格式和結構的,而不僅僅是一堆字串。預設情況下,每一行內容都是一條記錄,並以換行符(\n)結束。
(1)awk記錄分隔符-RS
記錄分隔符-每一個記錄(行)是如何結束的
- awk預設情況下每一行都是一個記錄(record)
- RS即record separator輸入資料記錄分隔符,每一行是怎麼沒的,表示每個記錄輸入的時候的分隔符,即行與行之間如何分隔。
- NR即number of record記錄(行)號,表示當前正在處理的記錄(行)的號碼
- ORS即output record separate輸出記錄分隔符
awk使用內建變數RS來存放輸入記錄分隔符,RS表示的是輸入的記錄分隔符,這個值可以通過BEGIN模組重新定義修改
[root@RedHat8-2 test]# head -2 awkfile.txt
root:x:0:0:root:/root:/bin/bash
bin:x:1:1:bin:/bin:/sbin/nologin
[root@RedHat8-2 test]# awk 'BEGIN{RS="/"}{print NR,$0}' 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:
....
#以:為每一行的結束
[root@RedHat8-2 test]# awk 'BEGIN{RS=":"}{print NR,$0}' awkfile.txt
#以連續的數字為每一行的結束
[root@RedHat8-2 test]# awk 'BEGIN{RS="[0-9]+"}{print NR,$0}' awkfile.txt
[root@RedHat8-2 test]# awk -v RS="[0-9]+" '{print NR,$0}' awkfile.txt
#awk -v 變數=值(變數是書的名字,值是書的內容)
在awk眼中,檔案是從頭到尾一段連續的字串,恰巧中間有些(\n回車換行符),\n也是字元。
\n就是換行,所以後面的內容到了下一行
(2)對$0的認識
如上圖可看出awk中$0表是整行,其實awk使用$0來表示整條記錄。記錄分隔符\n儲存在RS變數中。
另外awk對每一行的記錄號都有一個內建變數NR來儲存,每處理完一條記錄NR的值就會自動+1 。
1.4.2、按單詞出現頻率降序排序(計算檔案中每個單詞的重複數量)
注:(此處使用sort與uniq即可)
[root@RedHat8-2 test]# sed -r 's#[^a-zA-Z]+# #g' /etc/passwd> /root/count.txt
[root@RedHat8-2 test]# cat /root/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
operator x operator root sbin nologin
games x games usr games sbin nologin
ftp x FTP User var ftp sbin nologin
nobody x Kernel Overflow User sbin nologin
dbus x System message bus sbin nologin
systemd coredump x systemd Core Dumper sbin nologin
systemd resolve x systemd Resolver sbin nologin
tss x Account used by the trousers package to sandbox the tcsd daemon dev null sbin nologin
polkitd x User for polkitd sbin nologin
unbound x Unbound DNS resolver etc unbound sbin nologin
sssd x User for sssd sbin nologin
chrony x var lib chrony sbin nologin
sshd x Privilege separated SSH var empty sshd sbin nologin
pesign x Group for the pesign signing daemon var run pesign sbin nologin
rngd x Random Number Generator Daemon var lib rngd sbin nologin
test x home test sbin nologin
stu x home stu bin bash
stu x home stu bin bash
stu x home stu bin bash
stu x home stu bin bash
stu x home stu bin bash
stu x home stu bin bash
stu x home stu bin bash
stu x home stu bin bash
stu x home stu bin bash
stu x home stu bin bash
思路:
- 讓所有單詞排成一列,這樣每個單詞都會是單獨的一行
- 設定RS值為空格
- 將檔案裡面的所有空格替換為回車換行符“\n”
整體思路:想辦法讓所有單詞排成一列,站成一排,排序,合併重複的,顯示重複數量
[root@RedHat8-2 test]# awk 'BEGIN{RS="[^a-zA-Z]+"}{print $0}' /root/count.txt|sort|uniq -c|sort -rn
35 x
27 sbin
21 nologin
20 stu
15 bin
11 home
11 bash
8 var
4 User
4 systemd
4 root
4 daemon
3 the
3 sync
3 shutdown
3 pesign
3 mail
3 halt
3 games
3 for
3 adm
2 unbound
2 test
2 sssd
2 sshd
2 spool
2 rngd
2 polkitd
2 operator
2 lp
2 lib
2 ftp
2 chrony
1 usr
1 used
1 Unbound
1 tss
1 trousers
1 to
1 tcsd
1 System
1 SSH
1 signing
1 separated
1 sandbox
1 run
1 Resolver
1 resolver
1 resolve
1 Random
1 Privilege
1 package
1 Overflow
1 Number
1 null
1 nobody
1 message
1 lpd
1 Kernel
1 Group
1 Generator
1 FTP
1 etc
1 empty
1 Dumper
1 DNS
1 dev
1 dbus
1 Daemon
1 coredump
1 Core
1 by
1 bus
1 Account
sort :預設是按照 字母順序排列
-r :倒序
-n :按數字排序
uniq :把重複的合併成一行
-c:顯示重複出現的次數
[root@RedHat8-2 test]# awk 'BEGIN{RS=" "}{print $0}' /root/count.txt|sort|uniq -c|sort -rn
35 x
27 sbin
21 nologin
20 stu
15 bin
11 home
11 bash
8 var
4 User
4 systemd
4 root
4 daemon
3 the
3 sync
3 shutdown
3 pesign
3 mail
3 halt
3 games
3 for
3 adm
2 unbound
2 test
2 sssd
2 sshd
2 spool
2 rngd
2 polkitd
2 operator
2 lp
2 lib
2 ftp
2 chrony
1 usr
1 used
1 Unbound
1 tss
1 trousers
1 to
1 tcsd
1 System
1 SSH
1 signing
1 separated
1 sandbox
1 run
1 Resolver
1 resolver
1 resolve
1 Random
1 Privilege
1 package
1 Overflow
1 Number
1 null
1 nobody
1 message
1 lpd
1 Kernel
1 Group
1 Generator
1 FTP
1 etc
1 empty
1 Dumper
1 DNS
1 dev
1 dbus
1 Daemon
1 coredump
1 Core
1 by
1 bus
1 Account
1
一步一步來,先修改了RS,然後用NR除錯,看看到底如何分隔的。
然後通過sort排序,uniq去重。
1.4.3、awk記錄小結
- NR存放著每個記錄的號(行號)讀取新行時會自動+1
- RS是輸入資料的記錄的分隔符,簡單理解就是可以指定每個記錄的結尾標誌
- RS作用就是小事一個記錄的結束
- 當我們修改了RS的值,最好配合NR(行)來檢視變化,也就是修改了RS的值通過NR檢視結果,除錯awk程式
- ORS輸出資料的記錄的分隔符
1.4.4、欄位(列)
每條記錄都是由多個區域(field)組成的,預設情況下區域之間的分隔符是由空格(即空格或製表符)來分隔,並且將分隔符記錄在內建變數FS中,每行記錄的區域儲存在awk的內建變數NF中。
約定:
field有很多種解釋,域,記錄,區域。為了方便理解適用區域表示(field)
FS即field separator 輸入欄位(列)分隔符。把一行字串切為很多個區域。
NF即number of fileds,表示一行中列(欄位)的個數,可以理解為切成了多少份。
OFS使用內建變數FS來記錄區域分隔符的內容,FS可以在命令列上通過-F引數來更改,也可以通過BEGIN模組來更改
然後通過$n,n是整數,來取被切割後的區域,$1取第一個區域,$2取第二個區域,$NF取最後一個區域。
例項:
[root@RedHat8-2 ~]# awk '{print NF,$0}' count.txt
6 root x root root bin bash
6 bin x bin bin sbin nologin
6 daemon x daemon sbin sbin nologin
7 adm x adm var adm sbin nologin
8 lp x lp var spool lpd sbin nologin
6 sync x sync sbin bin sync
6 shutdown x shutdown sbin sbin shutdown
6 halt x halt sbin sbin halt
8 mail x mail var spool mail sbin nologin
6 operator x operator root sbin nologin
7 games x games usr games sbin nologin
8 ftp x FTP User var ftp sbin nologin
7 nobody x Kernel Overflow User sbin nologin
7 dbus x System message bus sbin nologin
8 systemd coredump x systemd Core Dumper sbin nologin
7 systemd resolve x systemd Resolver sbin nologin
17 tss x Account used by the trousers package to sandbox the tcsd daemon dev null sbin nologin
7 polkitd x User for polkitd sbin nologin
9 unbound x Unbound DNS resolver etc unbound sbin nologin
7 sssd x User for sssd sbin nologin
7 chrony x var lib chrony sbin nologin
10 sshd x Privilege separated SSH var empty sshd sbin nologin
13 pesign x Group for the pesign signing daemon var run pesign sbin nologin
11 rngd x Random Number Generator Daemon var lib rngd sbin nologin
6 test x home test sbin nologin
6 stu x home stu bin bash
6 stu x home stu bin bash
6 stu x home stu bin bash
6 stu x home stu bin bash
6 stu x home stu bin bash
6 stu x home stu bin bash
6 stu x home stu bin bash
6 stu x home stu bin bash
6 stu x home stu bin bash
6 stu x home stu bin bash
[root@RedHat8-2 ~]# echo "I am xiao,bai weixin is xxxxxx" >> /test/xiaobai.txt
[root@RedHat8-2 ~]# cd /test/
[root@RedHat8-2 test]# cat xiaobai.txt
I am xiao,bai weixin is xxxxxx
[root@RedHat8-2 test]# awk -F " |," '{print $3,$NF}' xiaobai.txt
xiao xxxxxx
[root@RedHat8-2 test]# awk -F " |," '{print $3","$NF}' xiaobai.txt
xiao,xxxxxx
[root@RedHat8-2 test]# awk -F "[ ,]" '{print $3","$NF}' xiaobai.txt
xiao,xxxxxx
在動作('{print $3,$NF}')中的逗號,表示空格,其實動作中的逗號就是OFS的值,剛開始吧逗號當作空格即可
[root@RedHat8-2 test]# ifconfig ens32|awk 'NR==2{print $1}'
inet
[root@RedHat8-2 test]# ifconfig ens32|awk -F "[ :]+" 'NR==2{print $1}'
[root@RedHat8-2 test]# ifconfig ens32|awk -F "[ :]+" 'NR==2{print $2}'
inet
##awk預設的FS 分隔符 空格序列 一個空格或多個空格 tab 都認為是一樣的一個整體
1.4.5、ORS與OFS簡介
現在說說ORS和OFS這兩個內建變數的含義
RS是輸入記錄分隔符,決定awk如何讀取或分隔每行(記錄)
ORS表示輸出記錄分隔符(output record separator),決定awk如何輸出一行(記錄)的,預設是回車換行(\n)
FS是輸入區域分隔符,決定awk讀入一行後如何再分為多個區域
OFS表示輸出區域分隔符,決定awk輸出每個區域的時候是用什麼分隔他們
awk無比強大,可以通過RS,FS決定awk如何讀取資料。也可以通過修改ORS,OFS的值指定awk如何輸出資料。
例:
調換/etc/passwd中第一列和最後一列位置
[root@RedHat8-2 test]# awk 'BEGIN{FS=":"}{print $NF,$2,$3,$4,$5,$6,$1}' awkfile.txt
/bin/bash x 0 0 root /root root
/sbin/nologin x 1 1 bin /bin bin
/sbin/nologin x 2 2 daemon /sbin daemon
/sbin/nologin x 3 4 adm /var/adm adm
/sbin/nologin x 4 7 lp /var/spool/lpd lp
/bin/sync x 5 0 sync /sbin sync
/sbin/shutdown x 6 0 shutdown /sbin shutdown
/sbin/halt x 7 0 halt /sbin halt
/sbin/nologin x 8 12 mail /var/spool/mail mail
/sbin/nologin x 11 0 operator /root operator
[root@RedHat8-2 test]# awk 'BEGIN{FS=":";OFS=":"}{print $NF,$2,$3,$4,$5,$6,$1}' awkfile.txt
/bin/bash:x:0:0:root:/root:root
/sbin/nologin:x:1:1:bin:/bin:bin
/sbin/nologin:x:2:2:daemon:/sbin:daemon
/sbin/nologin:x:3:4:adm:/var/adm:adm
/sbin/nologin:x:4:7:lp:/var/spool/lpd:lp
/bin/sync:x:5:0:sync:/sbin:sync
/sbin/shutdown:x:6:0:shutdown:/sbin:shutdown
/sbin/halt:x:7:0:halt:/sbin:halt
/sbin/nologin:x:8:12:mail:/var/spool/mail:mail
/sbin/nologin:x:11:0:operator:/root:operator
FS與OFS
awk 'BEGIN{FS=":";OFS="#"}{$1=$1;print $0}' file
這裡只是指定了FS和修改OFS,讓輸出分隔符。
上面的命令也可以寫成
awk 'BEGIN{FS=":";OFS="#"}{$1=$1}1' file
RS與ORS
awk 'BEGIN{RS="\n";ORS="#"}{print $0}' file
[root@RedHat8-2 test]# cat >abc.txt<<EOF
> a
> b
> c
> EOF
[root@RedHat8-2 test]# awk 'BEGIN{ORS="xty"}{print $0}' abc.txt
axtybxtycxty[root@RedHat8-2 test]#
(1)RS記錄分隔符,表示每行的結束標誌
(2)NR行號(記錄號)
(3)FS欄位分隔符,每列的分割標誌或結束標誌
(4)NF就是每行有多少列,每個記錄中欄位的數量
小結:
1) $符號表示取某個列(欄位),$1,$2,$NF
2) NF表示記錄中的區域(列)數量,$NF取最後一個列(區域)
3) FS(-F)欄位(列)分隔符 -F(FS) ":" <==> 'BEGIN{FS=";"}'
4) RS 記錄分隔符(行的結束標識)
5) NR行號
6) 選好合適的方式FS(***),RS,OFS,ORS
7) 分隔符==>結束標識
8) 記錄與區域,就對我們所謂的行與列,有了新的認識(RS,FS)
二、awk進階
2.1、awk模式與動作
awk的格式,裡面的模式動作,換句話說就是條件和做什麼
2.2、正則表示式作為模式
awk同sed一樣可以通過模式匹配來對輸入的文字進行匹配處理。模式匹配肯定少不了正則表示式,awk也支援大量的正則表示式模式,大部分與sed支援的元字元類似,而且正則表示式是玩轉三劍客的必備工具
下面表格列出了awk支援的正則表示式元字元:
元字元 |
功能 |
示例 |
解釋 |
^ |
字串開頭 |
/^xty/ $3~/^xty/ |
匹配所有以xty開頭的字串 匹配出所有第三列中以xty開頭 |
$ |
字串結尾 |
/xty$/ $3~/xty$/ |
匹配所有以xty結尾的(字串) 匹配第三列中以xty結尾的文字 |
. |
匹配任意單個字元 (包括回車符) |
/c..l/ |
匹配字母c,然後兩個任意字元,在以l結尾的行 |
* |
重複0個或多個前一個字元 |
/a*cool/ |
匹配0個或多個a之後緊跟著cool的行比如:cool、aaacool |
[] |
匹配指定字元內的任一個字元 |
/^[abc]/ |
匹配以字母a或b或c開頭的行 |
[^] |
匹配不再指定字元組內的任一個字元 |
/^[^abc]/ |
匹配不以字母a或b或c開頭的行 |
() |
子表示式組合 |
/(cool)+/ |
表示一個或多個cool組合,當有一些字元需要組合時,使用括號括起來 |
| |
或者的意思 |
/(cool)|B/ |
匹配錯了或者字母B的行 |
awk預設不支援的元字元,和需要新增引數才能支援的元字元 |
|||
x{m} x{m,} x{m,n} |
x重複m次 x重複至少m次 x重複至少m次,但不超過n次 需要指定引數: --posix或者 --re-interval 沒有該引數不能使用這種模式 |
/cool{5}/ |
需要注意一點的是,cool加括號或不加括號的區別,x可以使字串也可以是一個字元,所以/cool\{5\}/表示匹配coo在加上5個l,及coolllll, /\(cool\)\{2,\}/則表示匹配coolcoolcoolcool等 |
/(cool){2,}/ |
|||
/(cool){5,6}/ |
|||
2.2.1、awk正則表示式匹配操作符
awk正則匹配操作符
~:用於對記錄或區域的表示式進行匹配
!~:用於表達與~相反的意思
2.2.2、awk正則表示式匹配行
[root@RedHat8-2 test]# awk -F ":" '/^root/' awkfile.txt
root:x:0:0:root:/root:/bin/bash
和下面的效果是一樣的
[root@RedHat8-2 test]# awk -F ":" '$0~/^root/' awkfile.txt
root:x:0:0:root:/root:/bin/bash
說明:
awk只用正則表示式的時候預設匹配整行的即'$0~/^root/'與'/^root/'是一樣的
[root@RedHat8-2 ~]# awk '$3~/c/' count.txt
sync x sync sbin bin sync
tss x Account used by the trousers package to sandbox the tcsd daemon dev null sbin nologin
[root@RedHat8-2 ~]# awk '$3~/c$/' count.txt
sync x sync sbin bin sync
[root@RedHat8-2 ~]# awk '/c$/' count.txt
sync x sync sbin bin sync
[root@RedHat8-2 ~]# awk '$0~/c$/' count.txt
sync x sync sbin bin sync
2.3、練習
cat >/root/test/test.txt<<EOF
zhao yi 536489 50:100:30
qian er 125489 70:200:50
sun san 894563 60:50:30
li si 584965 80:90:5
zhou wu 224587 10:50:80
wu liu 336945 90:30:40
zheng qi 154785 70:60:50
wang ba 987452 40:10:70
EOF
## 第一列是姓氏
## 第二列是名字
## 第一第二列合起來就是姓名
## 第三列是對應的ID號碼
## 最後三列是三次充值金額
練習1:顯示zhao姓第二次充值金額和姓名
[root@RedHat8-2 test]# awk -F "[ :]+" '/^zhao/{print $2,$5}' test.txt
yi 100
[root@RedHat8-2 test]# awk -F "[ :]+" '/^zhao/{print $1$2,$5}' test.txt
zhaoyi 100
[root@RedHat8-2 test]# awk 'BEGIN{FS="[ :]+"}$1~/^zhao/{print $1$2,$5}' test.txt
zhaoyi 100
[root@RedHat8-2 test]# awk -F "[ :]+" '/^zhao/{print $1$2,$(NF-1)}' test.txt
zhaoyi 100
說明:
-F指定分隔符,-F即FS支援正則表示式
[ :]+ 表示連續空格或冒號
-F "[ :]+" 已連續冒號空格為分隔符
/^zhao/表示條件
{print $1$2,$(NF-1)}表示動作,滿足條件後,執行顯示第一列($1)和單數第二列($(NF-1))也可以
注意:
NF 是一行中有多少列,NF-1 整行就是倒數第二列
$(NF-1)就是取倒數第二列的內容
練習2:顯示liu的姓氏和ID號
[root@RedHat8-2 test]# awk '/liu/{print $1,$3}' test.txt
wu 336945
[root@RedHat8-2 test]# awk '$2~/^liu$/{print $1,$3}' test.txt
wu 336945
說明:
$2~/liu/表示條件,第二列包含liu時候執行對應的動作
{print $1,$3}表示動作,顯示第一列和第三列的內容
練習3:顯示所有以5開頭的ID號碼的人全名和ID號碼
[root@RedHat8-2 test]# awk '$3~/^5/{print $1$2,$3}' test.txt
zhaoyi 536489
lisi 584965
說明:
$3~/^5/是一個條件,表示匹配第三列以41開頭的。滿足條件後顯示出第一列第二列和第三列的內容
練習4:顯示所有以一個s或l開頭的名全名
[root@RedHat8-2 test]# awk '$2~/^[sl]/{print $1,$2}' test.txt
sun san
li si
wu liu
[root@RedHat8-2 test]# awk '$2~/^(s|l)/{print $1,$2}' test.txt
sun san
li si
wu liu
說明:
條件:$2~/^(s|l)/
這裡^(s|l)表示,以s或l開頭的文字(字串)
同時s或者l也可以使用括號表示式來實現,因為兩個字母所有括號表示式也可以[sl]表示s或者l
練習5:顯示所有ID號碼最後以為數字是2或3的人全名
[root@RedHat8-2 test]# awk '$3~/[23]$/{print $1$2}' test.txt
sunsan
wangba
[root@RedHat8-2 test]# awk '$3~/[23]$/{print $1,$2}' test.txt
sun san
wang ba
[root@RedHat8-2 test]# awk '$3~/(2|3)$/{print $1,$2}' test.txt
sun san
wang ba
練習6:顯示er的充值,每個值以¥開頭
[root@RedHat8-2 test]# awk -F "[ :]+" '$2~/^er$/{print "¥"$4,"¥"$5,"¥"$6}' test.txt
¥70 ¥200 ¥50
[root@RedHat8-2 test]# awk -F "[ :]+" -v OFS="¥" '$2~/^er/ {print "",$4" ",$5" ",$6}' test.txt
¥70 ¥200 ¥50
[root@RedHat8-2 test]# awk '$2~/^er$/{gsub(/:/,"$",$NF);print "$"$NF}' test.txt
$70$200$50
[root@RedHat8-2 test]# awk -F "[ :]+" '$2~/er/{print "¥"$4"¥"$5"¥"$6}' test.txt
¥70¥200¥50
[root@RedHat8-2 test]# awk '$2~/^er$/{gsub(/:/,"¥");print "¥"$NF}' test.txt
70¥200¥50
[root@RedHat8-2 test]# awk '$2~/^er$/{gsub(/:/,"¥",$NF);print "¥"$NF}' test.txt
¥70¥200¥50
說明:
動作部分是會常用到的拼接,print表示輸出內容如果後面的內容有雙引號,則雙引號裡面的內容原封不動輸出。
練習7:顯示所有人全名,以姓名格式無空格
[root@RedHat8-2 test]# awk '{print $1""$2}' test.txt
zhaoyi
qianer
sunsan
lisi
zhouwu
wuliu
zhengqi
wangba
[root@RedHat8-2 test]# awk -v OFS="," '{print $1$2}' test.txt
zhaoyi
qianer
sunsan
lisi
zhouwu
wuliu
zhengqi
wangba
2.4、比較表示式作為模式
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 |
例:
[root@RedHat8-2 test]# awk -F "[ :]+" '$5>100' test.txt
qian er 125489 70:200:50
[root@RedHat8-2 test]# awk -F "[ :]+" 'NR>=2&&NR<=5' test.txt
qian er 125489 70:200:50
sun san 894563 60:50:30
li si 584965 80:90:5
zhou wu 224587 10:50:80
[root@RedHat8-2 test]# awk -F "[ :]+" 'NR>=2 && NR<=5' test.txt
qian er 125489 70:200:50
sun san 894563 60:50:30
li si 584965 80:90:5
zhou wu 224587 10:50:80
例:
[root@RedHat8-2 test]# awk -F: '$5=="root"' /etc/passwd
root:x:0:0:root:/root:/bin/bash
[root@RedHat8-2 test]# awk -F: '$5~/^root$/' /etc/passwd
root:x:0:0:root:/root:/bin/bash
[root@RedHat8-2 test]# awk -F: '$5==root' awkfile.txt
[root@RedHat8-2 test]# #awk中 所有的字母 awk會認為是變數
2.5、範圍模式
pattern1 |
, |
pattern2 |
從哪裡來 |
到 |
哪裡去 |
條件1 |
, |
條件2 |
範圍模式簡單理解就是從哪裡來,到哪裡去。
匹配從條件1開始到條件2介紹的範圍
awk的範圍模式,與sed類似,但是又有不同,awk不能直接使用行號來作為範圍起始地址,因為awk具有內建變數NR來儲存記錄號,所有需要使用NR=1,NR=5這樣來使用。
範圍模式處理原則是:先匹配從第一個模式的首次出現到第二個模式的首次出現之間的內容,執行action。然後匹配從第一個模式的下一次出現到第二個模式的下一次出現,直到文字結束。如果匹配到第一個模式而沒有匹配到第二個模式,則awk處理從第一個模式開始直到文字結束全部行,如果第一個模式不匹配,就算第一個模式匹配,awk依舊不處理任何行。
[root@RedHat8-2 test]# awk 'NR==2,NR==5' 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
[root@RedHat8-2 test]# #範圍條件/範圍模式
2.5.1、BEGIN模組
BEGIN模組在awk讀取檔案之前就執行,一般用來定義我們的內建變數(預定義變數,eg:FS,RS),可以輸出表頭(類似excel表格名稱)
BEGIN模式,自定義變數,給內容變數賦值等,都是用過,需要注意的是BEGIN模式後面要接跟一夜action操作塊,包含在大括號內。awk必須在對輸入檔案進行任何處理前限制性BEGIN裡的動作(action)我們可以不要任何輸入檔案們就可以對BEGIN模組進行測試,因為awk需要限制性BEGIN模式,才對輸入檔案做處理。BEGIN模式常常被用來修改ORS,RS,FS,OFS等的值
2.6、取IP地址
[root@RedHat8-2 ~]# ifconfig ens32|awk -F "(inet )|( netmask)" 'NR==2{print $2}'
172.20.10.6
[root@RedHat8-2 ~]# ifconfig ens32|awk -F "[ :]+" 'NR==2{print $3}'
172.20.10.6
[root@RedHat8-2 ~]# ifconfig ens32|awk -F "[^0-9.]+" 'NR==2{print $2}'
172.20.10.6
也可以寫成:
[root@RedHat8-2 ~]# ifconfig ens32|awk 'BEGIN{FS="(inet )|( netmask)"} NR==2{print $2}'
172.20.10.6
[root@RedHat8-2 ~]# ifconfig ens32|awk 'BEGIN{FS="[ :]+"} NR==2{print $3}'
172.20.10.6
[root@RedHat8-2 ~]# ifconfig ens32|awk 'BEGIN{FS="[^0-9.]+"} NR==2{print $2}'
172.20.10.6
注: 命令列-F本質就是修改的FS變數
2.6.1、第二個作用,在讀取檔案之前輸出寫提示性資訊,表頭
顯示檔案awkfile.txt的第一列和第三列(前期準備的測試檔案 /etc/passwd前10行)並在第一行輸出username和UID
[root@RedHat8-2 test]# 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
operator 11
2.6.2、第三種用法,使用BEGIN模組的特殊性質進行測試
簡單輸出內容
[root@RedHat8-2 ~]# awk 'BEGIN{print "Hello !"}'
Hello !
執行計算
[root@RedHat8-2 ~]# awk 'BEGIN{print 10/3}'
3.33333
[root@RedHat8-2 ~]# awk 'BEGIN{print 10/3+2}'
5.33333
[root@RedHat8-2 ~]# awk 'BEGIN{print 10/3+2/4*9}'
7.83333
和變數相關的操作
[root@RedHat8-2 ~]# awk 'BEGIN{a=1;b=2;print a,b}'
1 2
[root@RedHat8-2 ~]# awk 'BEGIN{a=1;b=2;print a,b,a-b}'
1 2 -1
2.6.3、第四種用法:配合getline讀取檔案
直接定義,直接使用即可
awk中字母會被認為是變數,如果真的要給一個變數賦值字母(字串),使用雙引號。
[root@RedHat8-2 ~]# awk 'BEGIN{a=1;print a}'
1
[root@RedHat8-2 ~]# awk 'BEGIN{a="xiaobai";print a}'
xiaobai
說明:
沒有檔案awk依舊可以處理BEGIN模式下的動作(命令)
2.6.4、END模式
END在awk讀取完所有的檔案的時候,在執行END模組,一般用來輸出一個結果(累加,陣列結果),也可以是和BEGIN模組類似的結尾標識資訊。
[root@RedHat8-2 test]# awk 'BEGIN{print "name","ID"}{print $1$2,$3}END{print "Hello !" }' test.txt
name ID
zhaoyi 536489
qianer 125489
sunsan 894563
lisi 584965
zhouwu 224587
wuliu 336945
zhengqi 154785
wangba 987452
Hello !
2.6.5、統計/etc/services檔案裡面的空行數量
[root@RedHat8-2 test]# sed -n '/^$/p' /etc/services |wc -l
16
[root@RedHat8-2 test]# grep -n '^$' /etc/services |wc -l
16
[root@RedHat8-2 test]# grep -c '^$' /etc/services
16
[root@RedHat8-2 test]# awk '/^$/' /etc/services |wc -l
16
[root@RedHat8-2 test]# awk '/^$/{a++;print NR,a}' /etc/services
22 1
264 2
297 3
318 4
324 5
393 6
472 7
477 8
484 9
492 10
504 11
510 12
516 13
581 14
582 15
7844 16
[root@RedHat8-2 test]# awk '/^$/{i+=1}END{print i}' /etc/services
16
[root@RedHat8-2 test]# awk '/^$/{i=i+1}END{print i}' /etc/services
16
[root@RedHat8-2 test]# awk '/^$/{i++}END{print i}' /etc/services
16
[root@RedHat8-2 test]# awk '/^$/{a=a+1}END{print a}' /etc/services
16
[root@RedHat8-2 test]# awk '/^$/{c=c+1}END{print c}' /etc/services
16
#i++ == i=i+1
BEGIN awk中只能有一個
END awk中只能有一個
他倆可以同時出現。
第一步:統計空行個數
第二部:輸出最後結果
[root@RedHat8-2 test]# awk '/^$/{i=i+1}END{print i}' /etc/services
16
awk程式設計思想:
1.先處理,最後在END模式輸出。
2. {print NR,$0} body模組處理,處理完畢後
3. END{print "end of file"}輸出一個結果
awk的除錯技巧
讓awk顯示出每一步的執行結果
一般通過print來配合完成
幾種常用的運算表示式
i=i+1 ==>i++
i=i+2 ==> i+=2
i=i+$0 ==> i+=$0
2.7、總結:
1、awk命令核心由模式和動作組成,就是‘找誰{幹啥}’
2、模式就是條件,動作就是具體幹什麼
a、正則表示式:必須掌握正則
b、條件表示式:比大小,比較是否相等
c、範圍表示式:從哪裡來到哪裡
3. 注意BEGIN或END模組只能有一個。BEGIN{}BEGIN{}或END{}END{}都是錯誤的
4、找誰幹啥模組,可以是多個
a、'NR==2{print $1}NR==5{print $0}'
b、awk -F ":" 'NR==1{print NR,$0}NR==2{print NR,$NF}' awkfile.txt
內容為小白學習時的筆記,寫出來供大家參考