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 打印整行内容
1 1- 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编程的内容
发布了60 篇原创文章 · 获赞 3 · 访问量 2065

猜你喜欢

转载自blog.csdn.net/weixin_42313749/article/details/103647680