Bootstrap

正则表达式及文本处理三剑客(grep、sed、awk)

目录

一、正则表达式

1、正则表达式的概述

1.1 正则表达式的概念和作用

1.2 正则表达式支持的语言

1.3 正则表达式的优缺点

1.4 正则表达式的分类

1.4.1 基本正则表达式(BRE):

1.4.2 扩展正则表达式(ERE):

1.4.3 区别

1.5 帮助命令

 2、基础正则表达式

2.1 字符匹配

2.1.1 元字符点

2.1.2 字符组

2.2 匹配次数

2.3 位置锚定

2.4 分组或其他

2.4.1 分组

2.4.2 或者

2.4.3 非打印字符

3、扩展正则表达式

3.2 字符匹配

3.2 匹配次数

3.3 位置锚定

2.4 分组或其他

二、文本处理三剑客之grep

1、grep用法

2、grep案例

2.1 匹配qq号

2.2 匹配邮箱

2.3 匹配手机号

2.4 查询 /etc/passwd 文件中有 root 的行

2.5 将非#开头和非空白行的文本写入到其他文本

2.6 匹配行首和行尾单词相同的行

2.7 多个模式条件匹配

2.8 提取出字符串中的所有数字

2.9 统计文件单词个数

三、文本处理三剑客之sed

1、sed概述

1.1 sed概念

1.2 sed工作原理

1.3 sed优缺点

2、sed基本用法

3、sed搜索替换

4、sed分组查找替换

5、sed变量查找

6、使用sed工具修改配置文件

6.1 直接修改httpd的80端口

6.2 修改网卡名 

7、sed高级用法(了解)

四、文本处理三剑客之awk

1、awk的概述

2、awk基本用法

2.1 awk基本格式和执行流程

2.2 基本打印用法(动作 print)

2.3 常见的内置变量

2.5 模式PATTERN

2.6 awk结合数组运用

2.7 条件判断(if)

2.8 循环(for、while)

2.9 awk脚本(了解)

五、案例

1、统计当前主机的连接状态

2、统计当前连接主机数

3、过滤主机ip地址

4、 提取13:01到14:02之间的日志

5、提取下图ip地址及时间

6、提取host.txt主机名再放回host.txt文件

7、提取以数字形式显示/etc/passwd的权限

8、 统计/etc/fstab文件中每个文件系统类型出现的次数

9、打印偶数行

10、打印奇数行


一、正则表达式

1、正则表达式的概述

1.1 正则表达式的概念和作用

REGEXP(Regular Expressions)由一类特殊字符及文本字符所编写的模式,其中有些字符(元字符)不表示字符字面意义,而表示控制或通配的功能,类似于增强版的通配符功能,但与通配符不同,通配符功能是用来处理文件名,而正则表达式是处理文本内容

可用于匹配、搜索和替换文本。通过使用一系列的字符和元字符,以及特定的语法规则,正则表达式可以帮助你找到符合特定模式的文本

1.2 正则表达式支持的语言

vim, less,grep,sed,awk, nginx,mysql

1.3 正则表达式的优缺点

优点:

  • 强大的模式匹配能力:正则表达式能够描述复杂的字符串模式,包括匹配特定字符、重复次数、字符集合等,使其可以用于强大的模式匹配和搜索
  • 灵活性:正则表达式可以适应不同的文本模式,可以通过简洁而灵活的语法来描述各种匹配规则
  • 广泛支持:正则表达式在许多编程语言和工具中得到广泛支持,可以在不同平台和环境下使用
  • 文本处理和数据提取:正则表达式广泛用于文本处理、数据提取、文本替换等方面,能够快速、高效地进行字符串操作

缺点:

  • 复杂性:正则表达式的语法相对复杂,有一定的学习曲线,特别是在处理复杂模式时,编写和理解正则表达式可能会有一定的困难
  • 易读性:一些复杂的正则表达式可能难以阅读和理解,特别是对于不熟悉正则表达式的人来说,维护和修改这样的正则表达式可能会有困难
  • 性能:一些复杂的正则表达式可能会导致性能问题,特别是在大型文本上进行匹配时,需要谨慎设计正则表达式以避免性能瓶颈

1.4 正则表达式的分类

1.4.1 基本正则表达式(BRE):
  • 使用元字符时在其前面添加反斜线转义:\? 、 \+ 、 \{ 、 \} 、 \| 、 \( 和 \)
  •  grep sed默认使用基础正则表达式
1.4.2 扩展正则表达式(ERE):
  • 使用元字符时不需要在其前面添加反斜线转义:? 、 + 、 { 、 } 、 | 、 ( 和 )
  • grep -E、sed -r、egrep、awk扩展正则表达式
1.4.3 区别

元字符的区别

  • 基本正则表达式中需要使用反斜杠转义的方式来匹配特殊字符,比如\( \)代表分组,\{ \}代表重复次数,而|+等特殊字符需要使用反斜杠转义
  • 扩展正则表达式中通常不需要使用反斜杠转义来匹配特殊字符,比如()代表分组,{}代表重复次数,|+等特殊字符不需要转义

重复操作符的区别

  • 基本正则表达式+?等重复操作符不具备特殊含义,需要使用反斜杠转义来表示它们的特殊含
  • 扩展正则表达式+?等重复操作符可以直接使用,具有特殊含义

1.5 帮助命令

#可以使用 man 手册帮助
man 7 regex

 2、基础正则表达式

元字符

预订好且具有特殊含义的符号,这些符号能够进行通配

2.1 字符匹配

2.1.1 元字符点
.   	匹配任意单个字符,可以是一个汉字

r[.]t     在[ ]内的 . 代表原来的意思

 2.1.2 字符组
[ ]      	匹配指定范围内的任意单个字符
如:[0-9]     只匹配0~9范围内的任意单个数字
    [0-59]    表示匹配0~5和9而不是0~59
    [a-z]     只匹配a~z范围内的任意单个小写字母   
    [a-zA-Z]  只匹配a~z或A~Z范围内的任意单个字母

[^] 	    匹配指定范围外的任意单个字符,即取反。
注意 ^ 在括号内,在括号外代表行首,如:[^abcd]     匹配除a b c d外的其他所有字符

[[:alnum:]]= [0-9a-zA-Z] 	   匹配字母和数字
[[:alpha:]]= [a-zA-Z]	       代表任何英文大小写字符
[[:lower:]]=[a-z]	           小写字母
[[:upper:]]=[A-Z]       	   大写字母
[:blank:] 	   空白字符(空格和制表符)
[:space:] 	   水平和垂直的空白字符(比[:blank:]包含的范围广)
[:cntrl:] 	   不可打印的控制字符(退格、删除、警铃...)
[:digit:] 	   十进制数字
[:xdigit:]	   十六进制数字
[:graph:]      可打印的非空白字符
[:print:] 	   可打印字符
[:punct:]      匹配所有标点符号, ! " # $ % & ' ( ) * + , - . / : ; < = > ? @ [ \ ] ^ _ ` {
[:graph:]      图形字符,即能展现字符颜色的符号,等价于 [:alnum:] + [:punct:]

特殊元字符在中括号中的匹配:
想要在中括号中匹配 ^ ,需将其放在中括号的非开头位置,如[a^]
想要在中括号中匹配 - ,需将其放在开头位置或结尾位置,如[abc-]  [-abc]
想要在中括号中匹配 ] ,需将其放在开头位置或结尾位置,如[abc]]  []abc]
想要匹配上面2个或三个元字符,如[]^]  [-^]  []-]  []^-]

2.2 匹配次数

* 		匹配前面的字符任意次,包括 0 次
.* 		任意长度的任意字符
\? 		匹配其前面的字符 0 或 1 次,即:可有可无
\+ 		匹配其前面的字符至少 1 次,即:>=1
\{n\} 	匹配前面的字符 n 次
\{m,n\} 匹配前面的字符至少 m 次,至多 n 次
\{,n\} 	匹配前面的字符至多 n 次,<=n
\{n,\} 	匹配前面的字符至少 n 次

2.3 位置锚定

位置锚定可以用于定位出现的位置

^	行首锚定,用于模式的最左侧
$	行尾锚定,用于模式的最右侧
^$	空行
^[[:space:]]*$	空行或包含空白字符的行
^PATTERN$ 	    用于模式匹配整行
\< 或 \b 	    匹配单词边界,表示锚定词首,其后面的字符必须作为单词首部出现
\> 或 \b        匹配单词边界,表示锚定词尾,其前面的字符必须作为单词尾部出现
\<PATTERN\>     匹配整个单词

 2.4 分组或其他

2.4.1 分组
()    将多个字符捆绑在一起,当作一个整体处理,如:\(root\)+
2.4.2 或者
a\|b	    # a 或 b  
C\|cat	    # C 或 cat  
\(C\|c\)at	# Cat 或 cat
2.4.3 非打印字符
\n	匹配换行符
\r	匹配回车符
\t	匹配制表符
\w  匹配单词字符,相当于[a-zA-Z0-9_]
    单词字符包括字母、数字和下划线
\W  匹配非单词字符,相当于[^a-zA-Z0-9_]
\s  匹配空白字符
\S  匹配非空白字符
\d  匹配数字
\D  匹配非数字

3、扩展正则表达式

扩展正则表达式的元字符用法与基础正则表达式的元字符用法相差不大,区别在于扩展正则表达式不需要使用转义符,而基础正则表达式需要使用转义符

3.2 字符匹配

.   	匹配任意单个字符,可以是一个汉字
r[.]t   在[ ]内的 . 代表原来的意思 点
[ ]      	匹配指定范围内的任意单个字符
如:[0-9]     只匹配0~9范围内的任意单个数字
    [0-59]    表示匹配0~5和9而不是0~59
    [a-z]     只匹配a~z范围内的任意单个小写字母   
    [a-zA-Z]  只匹配a~z或A~Z范围内的任意单个字母

[^] 	    匹配指定范围外的任意单个字符,即取反。
注意 ^ 在括号内,在括号外代表行首,如:[^abcd]     匹配除a b c d外的其他所有字符

[[:alnum:]]= [0-9a-zA-Z] 	   匹配字母和数字
[[:alpha:]]= [a-zA-Z]	       代表任何英文大小写字符
[[:lower:]]=[a-z]	           小写字母
[[:upper:]]=[A-Z]       	   大写字母
[:blank:] 	   空白字符(空格和制表符)
[:space:] 	   水平和垂直的空白字符(比[:blank:]包含的范围广)
[:cntrl:] 	   不可打印的控制字符(退格、删除、警铃...)
[:digit:] 	   十进制数字
[:xdigit:]	   十六进制数字
[:graph:]      可打印的非空白字符
[:print:] 	   可打印字符
[:punct:]      匹配所有标点符号, ! " # $ % & ' ( ) * + , - . / : ; < = > ? @ [ \ ] ^ _ ` {
[:graph:]      图形字符,即能展现字符颜色的符号,等价于 [:alnum:] + [:punct:]

3.2 匹配次数

* 		匹配前面的字符任意次,包括 0 次
.* 		任意长度的任意字符
? 		匹配其前面的字符 0 或 1 次,即:可有可无
+ 		匹配其前面的字符至少 1 次,即:>=1
{n} 	匹配前面的字符 n 次
{m,n}   匹配前面的字符至少 m 次,至多 n 次
{,n} 	匹配前面的字符至多 n 次,<=n
{n,} 	匹配前面的字符至少 n 次

3.3 位置锚定

^	行首锚定,用于模式的最左侧
$	行尾锚定,用于模式的最右侧
^$	空行
^[[:space:]]*$	空行或包含空白字符的行
^PATTERN$ 	    用于模式匹配整行
\< 或 \b 	    匹配单词边界,表示锚定词首,其后面的字符必须作为单词首部出现
\> 或 \b        匹配单词边界,表示锚定词尾,其前面的字符必须作为单词尾部出现
\<PATTERN\>     匹配整个单词

2.4 分组或其他

()	分组

| 	或者
a|b 	  # a 或 b
C|cat 	  # C 或 cat
(C|c)at   # Cat 或 cat

\n	匹配换行符
\r	匹配回车符
\t	匹配制表符
\w  匹配单词字符,相当于[a-zA-Z0-9_]
    单词字符包括字母、数字和下划线
\W  匹配非单词字符,相当于[^a-zA-Z0-9_]
\s  匹配空白字符
\S  匹配非空白字符
\d  匹配数字
\D  匹配非数字

二、文本处理三剑客之grep

1、grep用法

grep 是一个强大的文本搜索工具,它可以在文件中查找特定模式的文本,并将包含这些模式的行进行筛选

grep  [选项]……  查找条件  源文件
-m	匹配指定次数后停止
-v	显示不被模式匹配到的行,取反
-i	忽略字符大小写
-n	显示行号
-c	统计匹配的行数
-o	仅显示匹配到的字符串
-q	静默模式,不输出任何信息
-e	实现多个选项间的逻辑 or 关系,如:grep -e "yellow" -e "red" file
-w	匹配整个单词
-E	使用扩展正则表达式,相当于 egrep
-F	不支持正则表达式,相当于 fgrep
-r	递归目录,但不处理软链接
-R	递归目录,但处理软链接
-f file	根据模式文件处理
-A n	after, 后 n 行
-B n	before, 前 n 行
-C n	context, 前后各 n 行

2、grep案例

2.1 匹配qq号

[root@localhost ~]#grep -Eo "\b[0-9]{6,12}\b" 1.txt

2.2 匹配邮箱

[root@localhost ~]#grep -Eo "[0-9a-zA-Z_]+@[0-9a-zA-Z_]+\.[0-9a-zA-Z_]+" 1.txt
[root@localhost ~]#grep -Eo "[[:alnum:]_-]+@[[:alnum:]_]+\.[[:alnum:]_]+" 1.txt

2.3 匹配手机号

[root@localhost ~]#grep -Eo "\b1[3456789][0-9]{9}\b" 1.txt 

2.4 查询 /etc/passwd 文件中有 root 的行

[root@localhost ~]#grep "root" /etc/passwd

2.5 将非#开头和非空白行的文本写入到其他文本

[root@localhost ~]#grep -Ev "^(#|$)" /etc/profile > 1.txt

2.6 匹配行首和行尾单词相同的行

[root@localhost ~]#grep "^\(.*\)\>.*\<\1$" /etc/passwd
[root@localhost ~]#grep -Eo "^(.*)\>.*\<\1$" /etc/passwd

2.7 多个模式条件匹配

#多个匹配条件之间的关系为或者
[root@localhost ~]#grep -e "root" -e "/bin/bash" /etc/passwd

2.8 提取出字符串中的所有数字

[root@localhost ~]#echo "Yd$C@M05MB%9&Bdh7dq+YVixp3vpw"|grep -o [0-9]

2.9 统计文件单词个数

[root@localhost data]#cat /etc/fstab |grep -Eo "\b[[:alpha:]]+\b"|wc -l
[root@localhost data]#cat /etc/fstab |grep -Eo "\b[[a-zA-Z]]+\b"|wc -l

三、文本处理三剑客之sed

1、sed概述

1.1 sed概念

  • sed 是一个流式文本编辑器,用于对文本进行替换、删除、插入等操作
  • 可在无交互的情况下实现相当复杂的文本处理操作
  • 被广泛应用于 Shell 脚本,以完成自动化处理任务

1.2 sed工作原理

  • 读取:sed 从输入流(文件、管道、标准输入)中读取一行内容并存储到临时的缓冲区中(又称模式空间,pattern space)
  • 执行:默认情况下,所有的 sed 命令都在模式空间中顺序地执行,除非指定行的地址,否则 sed 命令将会在所有的行上依次执行
  • 显示:发送修改后的内容到输出流。在发送数据后,模式空间将会被清空

1.3 sed优缺点

优点

  • 灵活强大的文本处理能力: sed 提供了丰富的文本处理命令和正则表达式支持,可以完成各种复杂的文本操作,如查找、替换、删除、插入等。它的功能强大且灵活,能够满足众多文本处理需求
  • 高效处理大型文件: sed 是基于流处理的工具,逐行读取和处理文本,因此在处理大型文件时非常高效,不会占用过多的内存和系统资源。这使得它适用于处理大量文本数据
  • 支持批量处理: sed 可以通过简单的命令一次性对多行文本进行处理,因此非常适合批量处理文本数据。它可以轻松地应用于一组文件或整个目录中的文件
  • 跨平台支持: sed 是一个跨平台的工具,可在不同的操作系统上(如Linux、UNIX、macOS等)使用。这使得它在各种环境中都能发挥作用,具有广泛的适用性。

缺点

  • 命令语法较复杂: sed 的命令语法相对较复杂,特别是对于初学者来说可能会有一定的学习曲线。对于一些复杂的处理任务,也可能需要深入了解正则表达式和高级命令才能灵活应用
  • 只能处理单行文本: sed 是基于行的文本处理工具,因此无法直接处理多行文本。它只能处理当前行,对于需要跨行操作的任务,可能会显得不够方便
  • 修改文件会覆盖原始数据: sed 默认情况下会直接修改文件内容,而不是将处理结果输出到标准输出。这意味着如果不小心操作,可能会不可逆地修改原始数据。因此,在使用 -i 选项时应格外小心
  • 不支持用户交互: sed 是一条命令行工具,通常在批处理环境下使用,并不支持与用户进行实时交互。这对于需要实时响应用户输入或交互的任务可能会有所不便

2、sed基本用法

(1)格式

sed  [option]...  'script;script;...'  [input  file...]
sed  [选项]       '自身脚本命令语法'    支持标准输入的文件

自身脚本命令语法=地址+脚本操作命令

 (2)选项

常用选项说明
-n不输出模式空间内容到屏幕,即不自动打印
-e

多点编辑,如sed -n -e '/^r/p'  -e'/^b/p' /etc/passwd

输出以r和以b开头的文本行

-f  FILE从指定文件中读取编辑脚本
-r, -E使用扩展正则表达式
-i.bak备份源文件为以".bak“结尾的文件(文件后缀名可随意),并源文件处继续编辑

(3)自身脚本命令语法

自身脚本命令语法=地址+脚本操作命令

①地址

地址说明
无地址空格对全文进行处理,如sed '  '  /etc/fstab=cat  /etc/fstab 查看文件内容
单地址#(数字)

指定的行,如sed  -n  '2p'  /etc/passwd 

只打印指定的第二行

$

最后一行,如sed  -n  '$p'  /etc/passwd   

只删除打印的最后一行(对源文件无影响)

/pattern/被此处模式所能够匹配到的每一行,正则表达式
地址范围m,n

从第 m 行到第 n 行

sed  -n  '1,3p'  /etc/passwd

只打印文件内容的第1到第3行

m,+n

从第 m 行到第 m+n 行

sed  -n  '1,+4p'  /etc/passwd

只打印文件内容的第1到第5行

/pat1/,/pat2/

第一个正则表达式和第二个正则表达式之间的行

如sed  -n  '/^r/,/^f/p'  /etc/passwd

打印以r开头的行到以f开头的行中间的所有行

 #,/pat/

从#行为开始找到 pat为止

如sed  -n  '3,/^f/p'  /etc/passwd

打印第三行到以b开头的行中间的所有行

/pat/,#

找到#号个pat为止

如sed  -n  '/^r/,3'  /etc/passwd

打印以r开头的行到第三行中间的所有行

步进1~2

奇数行, 第一个数为起始行后一个数字为前进步数

cat -n /etc/passwd | sed -n "1~2p" 

只打印文件里的奇数行内容

2~2

偶数行, 第一个数为起始行后一个数字为前进步数

cat -n /etc/passwd | sed -n "2~2p" 

只打印文件里的偶数行内容

②脚本操作命令

脚本操作命令说明
a

增加,在当前行下面增加一行指定内容,支持使用 \n 实现多行追加

i

插入,在选定行上面插入一行指定内容

c

替换,将选定行替换为指定内容

d

删除,删除选定的行

w   file

保存模式匹配的行至指定文件

r    file

读取指定文件的文本至模式空间中匹配到的行后

p

打印当前模式空间内容,追加到默认输出之后。

如果同时指定行,表示打印指定行;如果不指定行,则表示打印所有内容

Ip忽略大小写输出
模式空间中匹配行取反处理
=为模式空间中的行打印行号

 注:

以上的操作其实是对输出内容的修改,其实对源文件本身没有影响,如果想修改源文件,需启用 -i 选项

3、sed搜索替换

脚本操作命令说明
s替换,替换指定字符,格式 s/文件旧内容/替换的内容/修饰符
yy字符转换,和 s 用法类似,但只能替换大小写
g行内全局替换
p显示替换成功的行
I或者i忽略大小写
w  file将替换成功的行保存至文件中
[root@localhost ~]#sed 's/root/admin/g' /etc/passwd

[root@localhost ~]#sed 's/r..t/&er/g' /etc/passwd

4、sed分组查找替换

[root@localhost ~]#echo 123xyzabc |sed -r 's/123(xyz)abc/\1/'
[root@localhost ~]#echo 123xyzabc |sed -r 's/(123)(xyz)(abc)/\1\2/'
[root@localhost ~]#echo 123xyzabc |sed -r 's/(123)(xyz)(abc)/\3\2\1/'

5、sed变量查找

#先定义变量再用sed命令调用该变量值
root@localhost ~]#name=root
[root@localhost ~]#sed -nr "/$name/p" /etc/passwd    
[root@localhost ~]#sed -nr '/'$name'/p' /etc/passwd  #两单引号也可以查询

6、使用sed工具修改配置文件

sed可以用于修改配置文件,它可以从标准输入或文件中读取文本,并对其进行编辑和转换

6.1 直接修改httpd的80端口

[root@localhost ~]#grep "Listen" /etc/httpd/conf/httpd.conf
[root@localhost ~]#port=8080
[root@localhost ~]#sed -ri 's/^Listen 80/Listen '$port'/' /etc/httpd/conf/httpd.conf

 6.2 修改网卡名 

[root@localhost ~]#cat /etc/default/grub
[root@localhost ~]#sed -ri.bak '/^GRUB_CMDLINE_LINUX/s#(.*)"#\1 net.ifnames=0"#' /etc/default/grub
#使用分组替换,(.*)指得是 “号前面的所有,即在“号前,quiet后添加 net.ifnames=0(注意空格)
[root@localhost ~]#grep GRUB_CMDLINE_LINUX  /etc/default/grub

#其他方法
[root@localhost ~]#sed -ri.bak '/^GRUB_CMDLINE_LINUX/s#"$#net.ifnames=0"#' /etc/default/grub 
#直接将"号替换成"$#net.ifnames=0"


#修改完配置文件,注意重新生成grub配置文件
[root@localhost ~]#grub2-mkconfig -o /boot/grub2/grub.cfg 

7、sed高级用法(了解)

sed 中除了模式空间之外还支持保持空间(Hold Space),利用此空间,可以将模式空间中的数据临时保存至保持空间,从而后续接着处理,实现更为丰富的功能

P	打印模式空间开端至 \n 内容,并追加到默认输出之前
h	把模式空间中的内容覆盖至保持空间中
H	把模式空间中的内容追加至保持空间中
g	从保持空间取出数据覆盖至模式空间
G	从保持空间取出内容追加至模式空间
x	把模式空间中的内容与保持空间中的内容进行互换
n	读取匹配到的行的下一行覆盖至模式空间
N	读取匹配到的行的下一行追加至模式空间
d	删除模式空间中的行,也可以叫剪切
D	如果模式空间包含换行符,则删除直到第一个换行符的模式空间中的文本,并不会读取新的输入行,而使用合成的模式空间重新启动循环。如果模式空间不包含换行符,则会像发出 d 命令那样启动正常的新循环
[root@localhost ~]#sed -n 'N;p'  #奇数行
[root@localhost ~]#sed -n 'n;p'  #偶数行
[root@localhost ~]#sed -n 'n;P'  #偶数行

#将第一行和第二行合并成一行并指定分隔符
[root@localhost ~]#seq 10 | sed 'N;s/\n//'
[root@localhost ~]#seq 10 | sed 'N;s/\n/:/'

[root@localhost ~]#sed -n '1!G;h;$!d'    #倒序

四、文本处理三剑客之awk

1、awk的概述

awk是一个功能强大的编辑工具,逐行读取输入文本,默认以空格或tab键作为分隔符作为分隔,并按模式或者条件执行编辑命令。 用于从文件、管道或标准输入中读取文本,并根据用户指定的模式和操作进行处理

  • 文本提取和转换: 可以用 awk 提取文件中的特定字段或行,并对其进行转换和格式化。
  • 数据分析和报告生成: 可以利用 awk 对结构化数据进行分析,并生成报告、统计信息或汇总数据。
  • 文本格式化和处理: 可以使用 awk 对文本进行格式化、排序、过滤和合并等操作。
  • 自定义文本处理: 可以编写自定义的 awk 脚本来实现特定的文本处理逻辑,满足特定的需求

2、awk基本用法

2.1 awk基本格式和执行流程

awk [options]   'program' var=value   file…
      选项         语法      值       文件,支持标准输入、输出
awk         'pattern { action }'      input_file

注:

语法program通常是被放在单引号中,可分为pattern和action:
pattern:用于匹配输入文本的模式。可以使用正则表达式或字符串进行匹配。如果省略模式,则默认匹配所有行
action:对数据进行处理的操作,放在{}内指明,在满足模式的情况下要执行的动作。可以是单个命令或多个命令组合。如果省略动作,则默认打印整行。处理动作常见print、printf

①一定是单引号: '模式或条件{操作}'

② {}外指定条件,{}内指定操作

③ 内建变量不能使用双引号括起来,不然系统会把它当成字符串

执行流程:

① 执行BEGIN{action;… }{print}语句块中的语句
② 从文件或标准输入(stdin)读取一行,然后执行pattern{ action;… }语句块,它逐行扫描文件,
从第一行到最后一行重复这个过程,直到文件全部被读取完毕
③ 当读至输入流末尾时,执行END{action;…}语句块
BEGIN语句块在awk开始从输入流中读取行之前被执行,这是一个可选的语句块,比如变量初始化、打印输出表格的表头等语句通常可以写在BEGIN语句块中
END语句块在awk从输入流中读取完所有的行之后即被执行,比如打印所有行的分析结果这类信息汇总都是在END语句块中完成,它也是一个可选语句块
pattern语句块中的通用命令是最重要的部分,也是可选的。如果没有提供pattern语句块,则默认执行{ print },即打印每一个读取到的行,awk读取的每一行都会执行该语句块

常用选项说明
-F  "分隔符"指明输入时用到的字段分隔符
-f指定调用脚本
-v var=value变量赋值

2.2 基本打印用法(动作 print)

print item1,item2, ...

逗号做分隔符,用 {} 包起来
输出的 item 可以是字符串,也可是数值,当前记录的字段、变量或 awk 的表达式
如省略 item,相当于 print $0
[root@localhost ~]#awk ''      #program为空,没有效果
[root@localhost ~]#awk '{print}' /etc/passwd    #输出/etc/passwd文件所有内容
相当于cat /etc/passwd 和sed  ' '  /etc/passwd

[root@localhost ~]#awk -F: '{print $1,$7}' /etc/passwd
[root@localhost ~]#awk -F: '{print $1":"$7}' /etc/passwd
[root@localhost ~]#awk -F: '{print $1","$7}' /etc/passwd

2.3 常见的内置变量

内置变量说明
NR当前处理的行的行号(序数)
NF当前处理的行的字段个数
FS

指定每行文本的字段分隔符,默认为空格或制表位

与 “ -F ” 作用相同

OFS  输出内容的列分隔符
RS行分隔符,awk从文件中读取资料时,将根据RS的定义把资料切割成许多条记录, 而awk一次仅读入一条记录进行处理。预设值是"\n"
$0当前处理的行的整行内容
$n当前处理行的第n个字段(第n列)
FILENAME被处理的文件名

(1)NR:行号

当前处理的行的行号(序数)

[root@localhost ~]#awk -F: '{print $1,NR}' /etc/passwd
[root@localhost ~]#awk -F: '{print NR,$1}' /etc/passwd

[root@localhost ~]#awk 'NR==2{print $1}' /etc/passwd
[root@localhost ~]#awk 'NR==1,NR==3{print}' /etc/passwd
[root@localhost ~]#awk 'NR==1||NR==3{print}' /etc/passwd
[root@localhost ~]#awk 'NR>=3 && NR<=6{print NR,$0}' /etc/passwd
[root@localhost ~]#seq 10|awk 'NR>5 && NR<10'

#如何打印普通用户及其uid
[root@localhost ~]#awk -F: '$3>1000{print $3,$1}' /etc/passwd|sort -n

(2)NF

当前处理的行的字段个数

[root@localhost ~]#awk -F: '{print NF}' /etc/passwd
[root@localhost ~]#awk -F: '{print $NF}' /etc/passwd
[root@localhost ~]#awk -F: '{print $(NF-2)}' /etc/passwd

(3)FS

指定每行文本的字段分隔符,默认为空格或制表位,与 “ -F ” 作用相同

[root@localhost ~]#awk -F: '{print $1":"$3}' /etc/passwd
[root@localhost ~]#awk -v FS=':' '{print $1FS$3}' /etc/passwd

(4)OFS

输出内容的列分隔符

[root@localhost ~]#awk -v FS=':' -v OFS='==' '{print $1,$3}' /etc/passwd

(5)RS

行分隔符,awk从文件中读取资料时,将根据RS的定义把资料切割成许多条记录, 而awk一次仅读入一条记录进行处理。预设值是"\n"

[root@localhost ~]#echo $PATH | awk -v RS=":" '{print $1}'

(6)$0

当前处理的行的整行内容

[root@localhost ~]#awk -F: '{print $0}' /etc/passwd

(7) FILENAME

显示处理的文件名

[root@localhost ~]#awk -F: 'NR==2{print FILENAME}' /etc/passwd

2.5 模式PATTERN

(1)模式为空

 如果模式为空表示每一行都匹配成功,相当于没有额外条件

如:awk -F: '{print $1,$3}' /etc/passwd

(2)正则匹配

/regular expression/:仅处理能够模式匹配到的行,需要用/ /括起来

[root@localhost ~]#ifconfig ens33|awk '/netmask/{print}'
[root@localhost ~]#awk '/^root/{print}' /etc/passwd

 (3)line ranges:行范围

不支持使用行号,但是可以使用变量NR间接指定行号加上比较操作符或者逻辑关系

算术操作符
x+y, x-y, x*y, x/y, x^y, x%y
-x:转换为负数
+x:将字符串转换为数值

比较操作符:
==, !=, >, >=, <, <=

逻辑操作符
与:&&,并且关系
或:||,或者关系
非:!,取反

模式匹配符:
~  左边是否和右边匹配,包含关系
!~ 是否不匹配
$n (><==)用于对比数值
$n~"字符串"代表第n个字段,包含某个字符串的作用
$n!~"字符串"代表第n个字段,不包含某个字符串的作用
$n=="字符串"代表第n个字段为某个字符串的作用
$n!="字符串"代表第n个字段不为某个字符串的作用
$NF代表最后一个字段
#输出第七个字段包含“bash”所在行的第一个字段和最后一个字段
[root@localhost ~]#awk -F: '$7~"bash"{print $1,$NF}' /etc/passwd

#输出第七个字段不包含“nologin”所在行的第一个字段和最后一个字段
[root@localhost ~]#awk -F: '$7!~"nologin"{print $1,$NF}' /etc/passwd

#指定第六个字段为/home/dh,第七个字段为/bin/bash,输出满足这些条件的所在行
[root@localhost ~]#awk -F: '($6=="/home/dh")&&($7=="/bin/bash"){print $0}' /etc/passwd

(4)/pat1/,/pat2/

pat代表正则表达式,pat1到pat2  表示从正则表达式1到正则表达式2

#打印以r开头的行到以b开头的行中间的所有行
[root@localhost ~]#awk '/^r/,/^f/' /etc/passwd

 (5)关系表达式

在awk中,关系表达式用于比较两个值,并返回一个布尔值(真或假)。这些表达式通常用于控制流程和过滤数据,关系表达式结果为“真”才会被处理。

真:结果为非0值,非空字符串

假:结果为空字符串或0

[root@localhost ~]#echo 123 | awk '1{print}'     #1 允许打印
[root@localhost ~]#echo 123 | awk '0{print}'     #0 不允许打印

[root@localhost ~]# seq 5 | awk 'n++'
[root@localhost ~]# seq 5 | awk '!n++'
[root@localhost ~]# seq 5 | awk '!0'        #全部打印 

[root@localhost ~]# seq 5 | awk 'i=!i'      #打印奇数行
[root@localhost ~]# seq 5 | awk '!(i=!i)'   #打印偶数行  

(6) BEGIN END

BEGIN{}:仅在开始处理文件中的文本之前执行一次

END{}:仅在文本处理完成之后执行一次

[root@localhost ~]#awk -F: 'BEGIN {print "USERID USER"} {print $3,$1}' /etc/passwd
[root@localhost ~]#awk -F: '{print $3,$1} END{print "USERID USER"}' /etc/passwd
[root@localhost ~]#awk -F: 'BEGIN {print "USERID USER"} {print $3","$1} END{print "END FILE"}' /etc/passwd

#支持运算
[root@localhost ~]#awk 'BEGIN {print 2*2}'
[root@localhost ~]#awk 'BEGIN {print 6/2}'
[root@localhost ~]#awk 'BEGIN {print 6+2}'

2.6 awk结合数组运用

在awk中,数组是一种非常有用的数据结构,用于存储和操作数据。awk中的数组是关联数组,也就是说它们可以使用字符串作为索引。

awk数组特性:

①awk的数组是关联数组(即key/value方式的hash数据结构),索引下标可为数值(甚至是负数、小数等),也可为字符串

  • 在内部,awk数组的索引全都是字符串,即使是数值索引在使用时内部也会转换成字符串
  • awk的数组元素的顺序和元素插入时的顺序很可能是不相同的

②awk数组支持数组的数组

(1)awk中定义数组打印

可以使用数组的索引来访问和修改数组元素的值

[root@localhost ~]#awk 'BEGIN{a[0]=10;a[1]=20;a[2]=30;print a[0]}'
[root@localhost ~]#awk 'BEGIN{a[0]=10;a[1]=20;a[2]=30;print a[2]}'

(2)数组长度

awk提供了 length() 函数来获取数组的元素个数,它也可以用于获取字符串的字符数量。还可以获取数值转换成字符串后的字符数量

[root@localhost ~]#awk 'BEGIN{name["a"]="lcc";name["b"]="xz";name["c"]="dh";for(i in name)print name[i];print length(name)}'

(3)遍历数组

使用for循环来迭代数组中的元素

for(var in array)  {for-body}
awk 'BEGIN{name["a"]="zhangsan";name["b"]="lisi";name["c"]="wangwu";for(i in name)print name[i]}'

(4)awk打印文件内容去重统计

①去重打印数组

[root@localhost ~]#x=(10 10 10 20 30 20 30 20 40 10 30 10)
[root@localhost ~]#echo ${x[@]}|awk -v RS=' ' '!a[$1]++'

②处理文件去重统计

原理:将文件的字段内容变为定义的数组下标,对其进行匹配读取累加(只有遇到完全一致的才会累加),此时重复的次数在for循环的作用下成为了数组对应下标的元素,所以输出该下标和元素(就等同于输出重复的字段内容  以及统计的重复次数)

[root@localhost ~]#cat 1.txt 
[root@localhost ~]#awk '!a[$0]++' 1.txt

[root@localhost ~]#cat 1.txt 
[root@localhost ~]#awk '{a[$1]++};END{for(i in a){print i,a[i]}}' 1.txt

2.7 条件判断(if)

在awk中,条件判断通常用于控制程序的流程,以便根据特定条件执行不同的操作。条件判断通常与if语句结合使用

awk  选项  '模式 {actions}' 
#条件判断写在 actions里

if语句:awk的if语句也分为单分支、双分支和多分支

单分支为if(判断条件){执行语句}
双分支为if(判断条件){执行语句}else{执行语句}
多分支为if(判断条件){执行语句}else if(判断条件){执行语句}else if(判断条件){执行语句}else if(判断条件){执行语句}
[root@localhost ~]# awk -F: '{if($3>=1000){print $3,$1}else{print $1}}' /etc/passwd

2.8 循环(for、while)

在awk中,可以使用循环语句来重复执行一组操作,直到满足特定条件为止。awk支持for循环和while循环

awk  选项  '模式 {actions}' 
#循环语句写在 actions里
#condition为条件;statement为语句
for(expr1;expr2;expr3) {statement;…}
for(variable assignment;condition;iteration process) {for-body}
for(var in array) {for-body}
#计算1+2+3……+99+100的总和
[root@localhost ~]#awk 'BEGIN{sum=0;for(i=1;i<=100;i++){sum+=i};print sum}'

2.9 awk脚本(了解)

#!/bin/awk -f
{if($3>=1000){print $3,$1}}

五、案例

1、统计当前主机的连接状态

[root@localhost ~]#ss -nta | grep -v '^State' |cut -d" " -f1|sort |uniq -c
[root@localhost ~]#ss -nta|awk 'NR!=1{State[$1]++};END{for(i in State){print State[i],i}}'
[root@localhost ~]#ss -nat|awk 'NR!=1{print $1}' | sort |uniq -c

2、统计当前连接主机数

[root@localhost ~]#ss -nt |tail -n +2|tr -s " "|cut -d " " -f5|cut -d ":" -f1 |sort|uniq -c
[root@localhost ~]#ss -nt|awk -F "[ :]+" 'NR!=1{print $6}'|sort|uniq -c
[root@localhost ~]#ss -nt|awk -F "[ :]+" 'NR!=1{a[$6]++};END{for(i in a){print a[i],i}}'

3、过滤主机ip地址

[root@localhost ~]#ifconfig ens33|grep netmask|tr -s " "|cut -d " " -f3
[root@localhost ~]#ifconfig ens33 | sed -rn '2s/.*inet (.*) netmask.*/\1/p'
[root@localhost ~]#ifconfig ens33 | sed -rn '2s/.*inet ([0-9.]+) .*/\1/p'
[root@localhost ~]#ifconfig ens33 | awk '/netmask/{print $2}'

4、 提取13:01到14:02之间的日志

[root@localhost log]#sed -nr '/Jan 31 13:00:01/,/Jan 31 14:00:02/p' /var/log/messages
[root@localhost log]#awk '/Jan 31 13:00:01/,/Jan 31 14:00:02/{print $0}' /var/log/messages

5、提取下图ip地址及时间

[root@localhost data]#cat log.txt |sed -nr 's/(.*) - - \[(.*) \+.*/\1  \2/p'
[root@localhost data]#cat log.txt |awk -F"[[ ]" '{print $1,$5}'
[root@localhost data]#cat log.txt |awk -F"[[ ]+" '{print $1,$4}'

6、提取host.txt主机名再放回host.txt文件

[root@localhost data]#cat host.txt |awk -F"[ .]+" '{print $2}' >> host.txt
[root@localhost data]#cat host.txt |cut -d "." -f1 |tr -d "[0-9 ]"  >> host.txt
[root@localhost data]#cat host.txt |sed -nr 's/.* (.*)\.(.*)\.(.*)/\1/p'  >> host.txt

7、提取以数字形式显示/etc/passwd的权限

[dh@localhost ~]$stat /etc/passwd|awk -F"[(/]" 'NR==4{print $2}'
[dh@localhost ~]$stat /etc/passwd|sed -nr '4s/.*\(([0-9]{4}).*/\1/p'
[dh@localhost ~]$stat /etc/passwd|grep "权限"|cut -d ")" -f1|cut -d"(" -f2|cut -d"/" -f1

8、 统计/etc/fstab文件中每个文件系统类型出现的次数

[root@localhost ~]#cat /etc/fstab |awk '/^[^#]/{print $3}'|sort|uniq -c
[root@localhost ~]#grep -Ev "^(#|$)" /etc/fstab|awk '{print $3}'|sort -n|uniq -c
[root@localhost ~]#cat /etc/fstab |awk '/^[^#]/{a[$3]++};END{for(i in a){print a[i],i}}'

9、打印偶数行

[root@localhost ~]#echo {0..10..2}
[root@localhost ~]#seq 0 2 10
[root@localhost ~]#seq 10 | sed -n 'n;p'
[root@localhost ~]#seq 10 | sed -n '2~2p'
[root@localhost ~]#seq 10 | sed '1~2d'
[root@localhost ~]#seq 10 | sed -n '1~2!p'
[root@localhost ~]#seq 10 | awk '!(i=!i)'

10、打印奇数行

[root@localhost ~]#echo {0..10..2}
[root@localhost ~]#seq 0 2 10
[root@localhost ~]#seq 10 | sed -n 'n;p'
[root@localhost ~]#seq 10 | sed -n '2~2p'
[root@localhost ~]#seq 10 | sed '1~2d'
[root@localhost ~]#seq 10 | sed -n '1~2!p'
[root@localhost ~]#seq 10 | awk '!(i=!i)'
;