awk 文本處理詳解

awk 概述

AWK是一種優良的文本處理工具,Linux及Unix環境中現有的功能最強大的數據處理引擎之一。這種編程及數據操作語言的最大功能取決於一個人所擁有的知識。awk命名:Alfred Aho Peter 、Weinberger和brian kernighan三個人的姓的縮寫。

awk---->gawk 即: gun awk

在linux上常用的是gawk,awk是gawk的鏈接文件

man gawk---->pattern scanning and processing language模式掃描和處理語言。

pattern [pætn] 模式 ; process[prəʊses]處理

任何awk語句都是由模式和動作組成,一個awk腳本可以有多個語句。模式決定動作語句的觸發條件和觸發時間。

模式:

正則表達式 :/root/ 匹配含有root的行 /*.root/

關係表達式: < > && || + ***

匹配表達式: ~ !~

動作:

變量 命令 內置函數 流控制語句

它的語法結構如下:

awk [options] 'BEGIN{ print “start” }pattern{ commands }’END{ print “end” }'file

其中:BEGIN END是AWK的關鍵字部,因此必須大寫;這兩個部分開始塊和結束塊是可選的

awk 的鞏工作模式

和sed 命令類似,從上向下一次遍歷

語法格式:

  • awk ‘BEGIN{}parttern{commands} END{}’ file——name
  • stabdard output (標準輸出) |awk ‘BEGIN{} pattern{commands}END{}’

語法格式說明:

​ BEGIN{}:正式處理數據之前執行

​ pattern 匹配模式

​ {commands} 處理命令,可能多行

​ END{} 處理玩所有匹配數據後執行

awk 的內置變量

內置變量 含義
$0 打印整行內容
11-n 打印當前行的第1-n個字段
NF 當前行的字段個數,也就是有多少列
NR 當前行的行號,從1開始計數
FNR 多文件處理時,每個文件行號單獨計數,都是從0 開始
FS 輸入字段分割符,不指定默認以空格或tab鍵分割
RS 輸入行分割符,默認回車換行
OFS 輸入字段分割符,默認爲空格
ORS 輸出行分割符,默認爲回車換行
FILENAME 處理文件的文件名
ARGC 命令行參數個數
ARGV 命令行參數數組
  • $0 打印整行內容
[root@localhost ~]# awk '{print $0}' /etc/passwd
root:x:0:0:root:/root:/bin/bash
bin:x:1:1:bin:/bin:/sbin/nologin
……
postfix:x:89:89::/var/spool/postfix:/sbin/nologin
[root@localhost ~]# 

[root@localhost ~]# awk 'BEGIN{FS=":"} {print $1}' /etc/passwd #以:分隔符,打印第一字段
root
bin
daemon
adm
……
sshd
postfix
[root@localhost ~]# 

[root@localhost ~]# awk 'BEGIN{FS=":"} {print $2}' /etc/passwd 
#打印/etc/passwd 文件的第二個字段
x
x
x
……
x
x
[root@localhost ~]#  

# 打印每一行的第7個字段

[root@localhost ~]# awk 'BEGIN{FS=":"} {print $7}' /etc/passwd
/bin/bash
/sbin/nologin
/sbin/nologin
……
/sbin/nologin
/sbin/nologin
/sbin/nologin
/sbin/nologin
[root@localhost ~]# 

## 默認是以空格鍵和tab鍵 爲分隔符。如果不需要特定指定分隔符,就不需要加'BEGIN{FS="分隔符"}'
[root@hbs ~]# cat list 
Hadoop Spark Flume
Java Python Scala
Allen Mike Meggie
[root@hbs ~]# 

[root@hbs ~]# awk '{print $1}' list 
Hadoop
Java
Allen
[root@hbs ~]#

[root@hbs ~]# awk 'BEGIN{FS=":"} {print $NF}' /etc/passwd
/bin/bash
/sbin/nologin
/sbin/nologin
/sbin/nologin
……

# $NF 通常可以表示一行的最大值,最後一個數
  • NF 當前行的字段個數,也就是有多少列
[root@hbs ~]# vim list
[root@hbs ~]# cat list 
Hadoop Spark Flume                  #這行有3個字段
Java Python Scala	GO              #這行有4個字段   #tab鍵 沒有哦佔用啊
Allen Mike Meggie                   #這行有3個字段
[root@hbs ~]# 

[root@hbs ~]# awk '{print NF}' list 
3
4
3
[root@hbs ~]#

[root@hbs ~]# awk '{print NR}' list             #輸出行號有哪些
1
2
3
[root@hbs ~]# 
#當接多個文件後,發現他是累計計算的,so出現等多個文件就會單獨計數FNR
[root@hbs ~]# awk '{print NR}' list /etc/passwd   
1
2
3
4
5
6
7
……
21
[root@hbs ~]# 
[root@hbs ~]# awk '{print FNR}' list /etc/passwd  list和/etc/passwd 單獨計數
1
2
3
1 
2
3
4
……
17
18
[root@hbs ~]# 


  • FS 輸入字段分割符,不指定默認以空格或tab鍵分割
[root@hbs ~]# vim list 
[root@hbs ~]# cat list 
Hadoop|Spark:Flume
Java|Python:Scala:GO
Allen|Mike:Meggie

[root@hbs ~]# awk '{print $2}' list  #默認以空格爲分隔符,所以沒顯示


[root@hbs ~]# 
#以|符分隔    ‘BEGIN{FS="分割符"} {print $n}’ file
[root@hbs ~]# awk 'BEGIN{FS="|"} {print $1}' list 
Hadoop
Java
Allen
[root@hbs ~]# 
#以 : 分割 字段
[root@hbs ~]# awk 'BEGIN{FS=":"} {print $2}' list 
Flume
Scala
Meggie
[root@hbs ~]# 

  • RS 輸入行分割符,默認回車換行 默認是回車,如果不是回車,自定義的話需要RS 指定
[root@hbs ~]# cat tianzhen
Hadoop|Spark|Flume---java|Python|Scala|Go---Allen|Mike|Meggie
[root@hbs ~]# 
[root@hbs ~]# awk 'BEGIN{RS="---"} {print $0}' tianzhen 
Hadoop|Spark|Flume
java|Python|Scala|Go
Allen|Mike|Meggie

[root@hbs ~]# 

#先以行顯示,在以|分割
[root@hbs ~]# awk 'BEGIN{RS="---";FS="|"} {print $3}' tianzhen 
Flume
Scala
Meggie

[root@hbs ~]# 
  • ORS 輸出行分割符,默認爲回車換行
[root@hbs ~]# awk 'BEGIN{RS="---";FS="|";ORS="****"} {print $3}' tianzhen  
Flume****Scala****Meggie
****[root@hbs ~]# 

  • OFS
[root@hbs ~]# awk 'BEGIN{RS="***"};FS="---";OFS=":" {print $1,$3}' tianzhen 
Hadoop|Spark|Flume---java|Python|Scala|Go---Allen|Mike|Meggie
Hadoop|Spark|Flume---java|Python|Scala|Go---Allen|Mike|Meggie:
[root@hbs ~]# 

# 一般寫腳本時候,不會常用這三個
  • FILENAME 處理文件的文件名
[root@hbs ~]# awk '{print FILENAME}'  tianzhen (文件名)
tianzhen
tianzhen
tianzhen
[root@hbs ~]# 

[root@hbs ~]# awk '{print FILENAME}' list  (文件名)
list
list
list
[root@hbs ~]# 


awk 格式化輸出值printf

格式化 含義
%s 打印字符串
%d 打印十進制數字
%f 打印一個浮點數
%x 打印十六進制數
%o 打印八進制數字
%e 打印數字科學技術法形式
%c 打印單個字符的ASCII碼

printf 默認是沒有換行格式的

[root@hbs ~]# awk 'BEGIN{FS=":"} {printf $1}' /etc/passwd
rootbindaemonadmlpsyncshutdownhaltmailoperatorgamesftpnobodysystemd-networkdbuspolkitdsshdpostfix[root@hbs ~]# 

[root@hbs ~]# awk 'BEGIN{FS=":"} {printf "%s\n",$1}' /etc/passwd
root
bin
daemon
……
sshd
postfix
[root@hbs ~]# 

#打印第一個和第7個字段 
[root@hbs ~]# awk 'BEGIN{FS=":"} {printf "%s %s\n",$1,$7}' /etc/passwd
root /bin/bash
bin /sbin/nologin
daemon /sbin/nologin
……
sshd /sbin/nologin
postfix /sbin/nologin
[root@hbs ~]# 

#打印第一個和第7個字段 ,但是每個字段都需要站位20個字符串

[root@hbs ~]# awk 'BEGIN{FS=":"} {printf "%20s %20s\n",$1,$7}' /etc/passwd 
                root            /bin/bash
                 bin        /sbin/nologin
              daemon        /sbin/nologin
                 adm        /sbin/nologin
……
                dbus        /sbin/nologin
             polkitd        /sbin/nologin
                sshd        /sbin/nologin
             postfix        /sbin/nologin
[root@hbs ~]# 
# 這裏發現右邊對的是齊的,用+ - 號對齊,默認是左對齊

# 左對齊的方式打印
[root@hbs ~]# awk 'BEGIN{FS=":"} {printf "%-20s %-20s\n",$1,$7}' /etc/passwd
root                 /bin/bash           
bin                  /sbin/nologin       
daemon               /sbin/nologin       
……    
sshd                 /sbin/nologin       
postfix              /sbin/nologin       
[root@hbs ~]# 

格式舉例:

1、以字符串格式打印 /etc/passwd 的第7 個字段,一冒號 最爲分隔符

[root@hbs ~]# awk 'BEGIN{FS=":"} {printf "%s",$7}' /etc/passwd
/bin/bash/sbin/nologin/sbin/nologin/sbin/nologin/sbin/nologin/bin/sync/sbin/shutdown/sbin/halt/sbin/nologin/sbin/nologin/sbin/nologin/sbin/nologin/sbin/nologin/sbin/nologin/sbin/nologin/sbin/nologin/sbin/nologin/sbin/nologin[root@hbs ~]# 

# 加上回車換行
[root@hbs ~]# awk 'BEGIN{FS=":"} {printf "%s\n",$7}' /etc/passwd
/bin/bash
/sbin/nologin
……
/sbin/nologin
/sbin/nologin
[root@hbs ~]# 

# 多個換行
[root@hbs ~]# awk 'BEGIN{FS=":"} {printf "%s\n\n\n",$7}' /etc/passwd
/bin/bash


/sbin/nologin


/sbin/nologin


……

/sbin/nologin


[root@hbs ~]# 

2、以十進制格式打印 /etc/passwd 第三個字段,一冒號作爲分隔符

[root@hbs ~]# awk 'BEGIN{FS=":"} {printf "%d\n",$3}' /etc/passwd
0
1
2
3
……
81
999
74
89
[root@hbs ~]# 

常用就這2個,其它瞭解即可

awk 匹配的兩種用法

  • 迴歸工作模式:
讀取文本中的一行行數據,首先依據我們的pattern(匹配模式)匹配,如果匹配有就處理,沒有就不處理,繼續第二行匹配,有就處理,沒有就不匹配,繼續下一行,一直到匹配完所有文本

1 、 正則表達式

2、關係運算的匹配

正則匹配

匹配/etc/passwd 文件中含有root字符串的所有信息

[root@hbs ~]# awk 'BEGIN{FS=":"}/root/{print $0}' /etc/passwd
root:x:0:0:root:/root:/bin/bash
operator:x:11:0:operator:/root:/sbin/nologin
[root@hbs ~]# 


匹配/etc/passwd 文件中含有ftp 開頭的所有行

[root@hbs ~]# awk 'BEGIN{FS=":"}/^ftp/{print $0}' /etc/passwd
ftp:x:14:50:FTP User:/var/ftp:/sbin/nologin
[root@hbs ~]# 

關係運算符匹配

運算符 含義
< 小於
> 大於
<= 小於等於
>= 大於等於
== 等於
!= 不等於
~ 匹配正則表達式
!~ 不匹配正則表達式

以冒號爲分割符,匹配/etc/passwd 文件中第三個字小安與50的所有信息

[root@hbs ~]# awk 'BEGIN{FS=":"}$3<50{print $3}' /etc/passwd 
0
1
2
……
11
12
14
[root@hbs ~]# 

以冒號爲分割符,匹配/etc/passwd 文件中第三個字段大與50的所有信息

[root@hbs ~]# awk 'BEGIN{FS=":"}$3>50{print $3}' /etc/passwd 
99
192
81
999
74
89
[root@hbs ~]# 

以冒號爲分割符,匹配/etc/passwd 文件中第7個字段爲/bin/bash 的所有信息

[root@hbs ~]# awk 'BEGIN{FS=":"}$7=="/bin/bash"{print $0}' /etc/passwd
root:x:0:0:root:/root:/bin/bash
[root@hbs ~]# 

以 冒號分割符 ,匹配/etc/passwd 中第三個 字符串 包含3個以上數字的所有行信息

[root@hbs ~]# awk 'BEGIN{FS=":"}$3~/[0-9](3,)/{print $3}' /etc/passwd 
[root@hbs ~]# 


布爾運算符

||   或者

&&    與

!      非

以冒號爲分隔符 , 匹配/etc/passwd 文件中 包含ftp 或wyh 的所有行信息

[root@hbs ~]# awk 'BEGIN{FS=":"}$1=="ftp"||$1=="wyh"{print $0}' /etc/passwd
ftp:x:14:50:FTP User:/var/ftp:/sbin/nologin
[root@hbs ~]# 


以冒號分割符,匹配 /etc/passwd 文件中第三個字段小於50 並且第4個字段大於50的所有信息

[root@hbs ~]# awk 'BEGIN{FS=":"}$3<=50 && $4 >= 50 {print $0}'  /etc/passwd
games:x:12:100:games:/usr/games:/sbin/nologin
ftp:x:14:50:FTP User:/var/ftp:/sbin/nologin
[root@hbs ~]# 


awk 動作中的表達式用法

運算符 含義
+
-
*
/
^或者** 乘方
++X 在返回x變量前,x變量+1 (加在前,先+)
X++ 在返回後,x變量+1
[root@hbs ~]# awk 'BEGIN{var=20;var1="hello";print var,var1}' 
20 hello
[root@hbs ~]#
# num1 沒有定義 ,默認爲0
[root@hbs ~]# awk 'BEGIN{num1=20;num2+=num1;print num1,num2}'
20 20
[root@hbs ~]# 

# num 2 除以 num 1 
[root@hbs ~]# awk 'BEGIN{num1=20;num2=100;print num2/num1}'
5
[root@hbs ~]# 

[root@hbs ~]# awk 'BEGIN{num1=20;num2=30;printf "%f\n",num1/num2}'
0.666667
[root@hbs ~]# 



awk 動作中的條件及循環語句

  • 條件語句
if(條件表達式)
	動作1
else if(條件表達式)
	動作2
else
	動作3
	
以冒號 分割符  ,值打印 /etc/passwd 中第3個字段的數值在50~100 範圍內的信息
[root@hbs ~]# awk 'BEGIN{FS=":"}{if($3>50 && $3<100) print $0}' /etc/passwd
nobody:x:99:99:Nobody:/:/sbin/nologin
dbus:x:81:81:System message bus:/:/sbin/nologin
sshd:x:74:74:Privilege-separated SSH:/var/empty/sshd:/sbin/nologin
postfix:x:89:89::/var/spool/postfix:/sbin/nologin
[root@hbs ~]# 

等價於這樣:
[root@hbs ~]# awk 'BEGIN{FS=":"}$3 >=50 && $3 <=100{print $0}' /etc/passwd
nobody:x:99:99:Nobody:/:/sbin/nologin
dbus:x:81:81:System message bus:/:/sbin/nologin
sshd:x:74:74:Privilege-separated SSH:/var/empty/sshd:/sbin/nologin
postfix:x:89:89::/var/spool/postfix:/sbin/nologin
[root@hbs ~]# 

[root@hbs ~]# awk 'BEGIN{FS=":"}{if($3<50) printf "%s%d","小於50的uid",$3}' /etc/passwd
小於50的uid0小於50的uid1小於50的uid2小於50的uid3小於50的uid4小於50的uid5小於50的uid6小於50的uid7小於50的uid8小於50的uid11小於50的uid12小於50的uid14[root@hbs ~]# 

# 沒加 \n 換行的效果

[root@hbs ~]# awk 'BEGIN{FS=":"}{if($3<50) printf "%s%d\n","小於50的uid",$3}' /etc/passwd
小於50的uid0
小於50的uid1
小於50的uid2
小於50的uid3
小於50的uid4
小於50的uid5
小於50的uid6
小於50的uid7
小於50的uid8
小於50的uid11
小於50的uid12
小於50的uid14
[root@hbs ~]# 


[root@hbs ~]# awk 'BEGIN{FS=":"}{if($3<50) printf "%-10s %-5d\n","小於50的uid",$3}' /etc/passwd
小於50的uid   0    
小於50的uid   1    
小於50的uid   2    
小於50的uid   3    
小於50的uid   4    
小於50的uid   5    
小於50的uid   6    
小於50的uid   7    
小於50的uid   8    
小於50的uid   11   
小於50的uid   12   
小於50的uid   14   


  • 循環語句 do while
do while
	do
			動作
	while (條件表達式)

  • for循環
for
	for (初始化計數器;計數器測試;計數器變更)
		動作

計算1+2+3+4+5+……+100的和,請使用while、do while、for 三種循環方式實現

while  循環

[root@hbs ~]# cat while.sh 
BEGIN {
	while (i<=100)
	{	
	  sum+=i
	  i++
         }
	print sum
 }

[root@hbs ~]# awk -f while.sh   # -f引用
5050
[root@hbs ~]# 


for 循環
[root@hbs ~]# cat for.sh 
BEGIN{
	for(i=0;i<=100;i++)
	{
		sum+=i
	}
	print sum
 }
[root@hbs ~]# awk -f for.sh 
5050
[root@hbs ~]# 



do while 

[root@hbs ~]# cat do_while.sh 
BEGIN{
	do	
	{
		sum+=i
		i++
	}
	while (i<=100)
	print sum
}
[root@hbs ~]# awk -f do_while.sh 
5050
[root@hbs ~]# 

awk 選項總結

選項 含義
-v 參數傳遞
-f 指定腳本文件
-F 之地那個分割符
-V 查看awk的版本號

-v 定義或引用變量

[root@hbs ~]# awk -v num2="$num1" -v var1="$var" 'BEGIN{print num2,var1}'
20 hello
[root@hbs ~]# 


-f 指定awk 命令文件

[root@hbs ~]# cat do_while.sh 
BEGIN{
	do	
	{
		sum+=i
		i++
	}
	while (i<=100)
	print sum
}
[root@hbs ~]# awk -f do_while.sh 
5050
[root@hbs ~]# 

-F 指定分割符

[root@hbs ~]# awk 'BEGIN{FS=":"}{print $1}' /etc/passwd
root
bin
……
sshd
postfix
[root@hbs ~]# 

[root@hbs ~]# awk -F ":" '{print $1}' /etc/passwd
root
bin
daemon
……
sshd
postfix
[root@hbs ~]# 


-V 查看awk 版本號

[root@hbs ~]# awk -V
GNU Awk 4.0.2
Copyright (C) 1989, 1991-2012 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/.
[root@hbs ~]# 


  • 關於awk 的用法,其實還有很多,包括後面的awk數組中用法等等,如果感興趣的話,您可以留言,大家一起研究awk編程的內容
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章