三剑客命令grep sed awk

剑客之grep命令

grep介绍

grep命令主要用于过滤文本,grep家族如下

grep: 在文件中全局查找指定的正则表达式,并打印所有包含该表达式的行
egrep:扩展的egrep,支持更多的正则表达式元字符
fgrep:固定grep(fixed grep),有时也被称作快速(fast grep),它按字面解释所有的字符

grep命令格式如下

grep [选项] PATTERN 文件1 文件2 ...

[root@egon ~]# grep 'root' /etc/passwd
[root@egon ~]# fgrep 'bash' /etc/passwd

找到:				grep返回的退出状态为0
没找到:				grep返回的退出状态为1
找不到指定文件:	  	grep返回的退出状态为2

grep 命令的输入可以来自标准输入或管道,而不仅仅是文件,例如:

ps aux | grep 'nginx'

选项

-n, --line-number			在过滤出的每一行前面加上它在文件中的相对行号
-o, --only-matching			只显示匹配的内容
-q, --quiet, --silent		静默模式,没有任何输出,得用$?来判断执行成功没有,即有没有过滤到想要的内容
--color						颜色
-i, --ignore-case			忽略大小写
-A, --after-context=NUM		如果匹配成功,则将匹配行及其后n行一起打印出来
-B, --before-context=NUM	如果匹配成功,则将匹配行及其前n行一起打印出来
-C, --context=NUM			如果匹配成功,则将匹配行及其前后n行一起打印出来
-c, --count					如果匹配成功,则将匹配到的行数打印出来
-v, --invert-match			反向查找,只显示不匹配的行
-w							匹配单词
-E							等于egrep,扩展

-l, --files-with-matches	如果匹配成功,则只将文件名打印出来,失败则不打印
							通常-rl一起用,grep -rl 'root' /etc 							
-R, -r, --recursive			递归

正则表达式

正则表达式,又称规则表达式。正则表达式由元字符组成,通常被用来检索、替换那些符合某个模式(规则)的文本(许多程序设计语言都支持利用正则表达式进行字符串操作)。

元字符:是一类可以表达出超越其字面本身含义的特殊字符

shell元字符(也称为通配符): 由shell解释器来解析,如rm -rf *.txt,元字符*,Shell将其解析为任意多个字符
正则表达式元字符 : 由各种执行模式匹配操作的程序来解析,比如vi、grep、sed、awk

基本正则元字符集

元字符		  功能										       示例	
^ 			  行首										      ^love
$ 			  行尾										      love$
. 			  除了换行符以外的任意单个字符					      l..e
* 			  前导字符的零个或多个						      ab*love
.* 			  所有字符										  a.*love
[] 			  字符组内的任一字符								  [lL]ove
[^] 		  对字符组内的每个字符取反(不匹配字符组内的每个字符)    [^a-z0-9]ove
^[^] 	      非字符组内的字符开头的行

[a-z] 		  小写字母
[A-Z] 		  大写字母
[a-Z] 	      小写和大写字母
[0-9] 	      数字

\	  		  用来转义元字符 									       love\.	
\< 		      词首定位符 单词一般以空格或特殊字符做分隔、连续的字符组成   \<love
\> 			  词尾定位符										       love\>
(..)		  匹配稍后将要使用的字符的标签	                          \(love\).*\1er	

x\{m\}				字符x重复出现m次							         x\{3\}
x\{m,\}				字符x重复出现m次以上								 x\{3,\}						
x\{m,n\}		    字符x重复出现m到n次								 x\{3,6\}	

关于(…)使用讲解

[root@m01 ~]# cat a.txt 
lovesshoqsoqsjoqloveer
[root@m01 ~]# grep -E "(love).*\1er" a.txt				# \1表示(..)的数据
lovesshoqsoqsjoqloveer

扩展正则元字符集

扩展正则元字符
+					匹配一个或多个前导字符		    [a-z]+ove	
?					匹配零个或一个前导字符		    lo?ve	
a|b					匹配a或b					    love|hate
()					组字符						love(able|rs)  (nana)+
(..)(..)\1\2		标签匹配字符				    (love).*\1er
x{n}			    x出现n次				  	    x{3}		
x{n,}			    x出现n次至无穷次			    x{3,}
x{n,m}		        x出现n次至m次			    x{3,6}

若想使用扩展正则
grep加-E 或 egrep 或转义\

sed 加 -r 参数 或转义\

AWK 直接支持大多数扩展正则,更多支持需要加选项--posix选项

只显示ip a命令输出结果的ip地址和子网掩码

[root@m01 ~]# ip a | grep -Eo "([0-9]{1,3}\.){3}[0-9]{1,3}/[0-9]{1,2}"
127.0.0.1/8
192.168.15.61/24
172.16.1.61/24

总结

grep:				使用基本元字符集	^, $, ., *, [], [^], \< \>,\(\),\{\}
egrep(或grep -E):	使用扩展元字符集	?, +, { }, |, ( )
# 注:grep也可以使用扩展集中的元字符,仅需要对这些元字符前置一个反斜线

\w	所有字母与数字,称为字符[a-zA-Z0-9]	   'l[a-zA-Z0-9]*ve'	   		'l\w*ve'
\W	所有字母与数字之外的字符,称为非字符	   'love[^a-zA-Z0-9]+' 	        'love\W+'
\b	词边界									'\80\b'					  '\<80\>'

剑客之sed命令

sed介绍

注意sed需要用' '!!!

sed全称流式编辑器,非交互式编辑文件。
在这里插入图片描述

sed和grep不一样,不管是否找到指定的模式,它的退出状态都是0,所以我们无法使用$?对上一条命令的执行结果进行判断。
只有当命令存在语法错误时,sed的退出状态才不是0。

sed命令格式如下

sed 选项 '定位+命令' 文件路径

选项

选项 功能
-e : 允许多项编辑
-n : 取消默认的输出(模式空间的内容输出)
-i : inplace,就地编辑
-r : 支持扩展元字符
-f : 指定sed脚本文件名

[root@m01 ~]# sed -r '' a.txt
111
222
333
[root@m01 ~]# sed -r '1p' a.txt
111
111
222
333
[root@m01 ~]# sed -rn '1p' a.txt
111
[root@m01 ~]# sed -rni '1p' a.txt
[root@m01 ~]# cat a.txt
111
[root@m01 ~]# cat a.txt
111
222
333
444
555
666
777

-e 参数定位进行操作的行
写法一:
[root@m01 ~]# sed -r -e '3d' -e '4p' a.txt
111
222
444
444
555
666
777

写法二:
[root@m01 ~]# sed -r '3d;4p' a.txt
111
222
444
444
555
666
777

写法三:
-f 指定运行规则的文件路径
[root@m01 ~]# vim b.txt
3d 
4p
[root@m01 ~]# sed -r -f b.txt a.txt		
111
222
444
444
555
666
777

地址用于决定对流入模式空间的哪些行进行编辑,如果没有指定地址,sed将处理流入模式空间的所有行。
地址可以是

  • 1、数字
,删除1-6行
[root@m01 ~]# sed -r '1,6d' a.txt
777

;删除1行3行和6行
[root@m01 ~]# sed -r '1d;3d;5d' a.txt
222
444
666
777

删除3行到最后一行
[root@m01 ~]# sed -r '3,$d' a.txt
111
222
  • 2、正则表达式
[root@m01 ~]# cat A.txt 
111111
222222666
55555lol55555
ll66666ll
222333ppp
[root@m01 ~]# sed -r '' A.txt
111111
222222666
55555lol55555
ll66666ll
222333ppp
[root@m01 ~]# sed -r '/lol/d' A.txt
111111
222222666
ll66666ll
222333ppp
[root@m01 ~]# sed -r '/ppp$/d' A.txt
111111
222222666
55555lol55555
ll66666ll
[root@m01 ~]# sed -r '/^55.*55$/d' A.txt
111111
222222666
ll66666ll
222333ppp
[root@m01 ~]# sed -rn '/^55.*55$/p' A.txt
55555lol55555
[root@m01 ~]# sed -r '' c.txt
/etc/passwd
abc
111
222
[root@m01 ~]# sed -rn '/^\//p' c.txt
/etc/passwd
[root@m01 ~]# cat A.txt 
111111
222222666
55555lol55555
ll66666ll5555
222333ppp5555

行号+正则表达式混合使用(了解即可,范围匹配)
[root@m01 ~]# sed -r '2,/5$/d' A.txt
111111
ll66666ll5555
222333ppp5555

sed常用命令

sed命令告诉sed对指定行进行何种操作,包括打印、删除、修改等。

命令功能
a在当前行后添加一行或多行
c用新文本修改(替换)当前行中的文本
d删除行
i在当前行之前插入文本
l会用$符号标识出文件中看不到的字符的位置
p打印行
n把下一行内容读入模式空间,后续的处理命令处理的都是刚读入的新内容
q结束或退出sed,不会将后续内容读入模式空间
r从文件中读
!对所选行以外的所有行应用命令
s用一个字符串替换另一个
w将行写入文件
y将字符转换为另一字符(不支持正则表达式),y/haha/1234/ h->1 a->2 h->3 a->4
h把模式空间里的内容复制到暂存缓冲区(覆盖)
H把模式空间里的内容追加到暂存缓冲区
g取出暂存缓冲区的内容,将其复制到模式空间,覆盖该处原有内容
G取出暂存缓冲区的内容,将其复制到模式空间,追加在原有内容后面
x交换暂存缓冲区与模式空间的内容
替换标志s
g在行内进行全局替换
i忽略大小写
[root@m01 ~]# sed -r '' A.txt
111111
222222666
55555lol55555
ll66666ll5555
222333ppp5555

对1-3行做处理,先打印再删除
[root@m01 ~]# sed -r '1,3{p;d}' A.txt
111111
222222666
55555lol55555
ll66666ll5555
222333ppp5555

s默认从左到右匹配第一个
[root@m01 ~]# sed -r 's/ll/AA/' A.txt
111111
222222666
55555lol55555
AA66666ll5555
222333ppp5555

先定位行号,再进行匹配s///g,从左到右全部匹配
[root@m01 ~]# sed -r '1,3s/55/AA/g' A.txt
111111
222222666
AAAA5lolAAAA5
ll66666ll5555
222333ppp5555

正则匹配先定位行号,s///g,ll全部替换成S
[root@m01 ~]# sed -r '/^ll/s/ll/S/g' A.txt
111111
222222666
55555lol55555
S66666S5555
222333ppp5555

=======================================================================================================================
[root@m01 ~]# cat A.txt 
111111
222222666
55555lol55555
ll66666ll5555
222333ppp5555
LLAAALL

i忽略大小写
[root@m01 ~]# sed -r 's/ll/S/ig' A.txt
111111
222222666
55555lol55555
S66666S5555
222333ppp5555
SAAAS

&将匹配成功的结果取出来,进行追加拼接
[root@m01 ~]# sed -r 's/[0-9]$/&.change/' A.txt
111111.change
222222666.change
55555lol55555.change
ll66666ll5555.change
222333ppp5555.change
LLAAALL

将配置文件中数字和字母顺序做替换
[root@m01 ~]# sed -r 's/([a-zA-Z]+)([^a-zA-Z]+)/\2\1/' A.txt
111111
222222666
5555555555lol
66666llll5555
2223335555ppp
LLAAALL

定位到某一行,先执行第一个命令,再执行第二个命令
定位到1-5行,先执行p命令,再执行s命令
[root@m01 ~]# sed -r '1,5{p;s/ll/S/gi}' A.txt
111111
111111
222222666
222222666
55555lol55555
55555lol55555
ll66666ll5555
S66666S5555
222333ppp5555
222333ppp5555
LLAAALL

=======================================================================================================================
!取反
[root@m01 ~]# sed -r '1,5d' A.txt
LLAAALL
[root@m01 ~]# sed -r '1,5!d' A.txt
111111
222222666
55555lol55555
ll66666ll5555
222333ppp5555

r在指定行后面追加
[root@m01 ~]# sed -r '3a 66666' A.txt
111111
222222666
55555lol55555
66666
ll66666ll5555
222333ppp5555
LLAAALL

i指定行前面追加
[root@m01 ~]# sed -r '3i 66666' A.txt
111111
222222666
66666
55555lol55555
ll66666ll5555
222333ppp5555
LLAAALL

c指定行进行修改
[root@m01 ~]# sed -r '3c 66666' A.txt
111111
222222666
66666
ll66666ll5555
222333ppp5555
LLAAALL

=======================================================================================================================
[root@m01 ~]# cat a.txt
111
222
444
444
555
666
777

[root@m01 ~]# cat A.txt
111111
222222666
55555lol55555
ll66666ll5555
222333ppp5555
LLAAALL

将a.txt的文件内容追加到A.txt第4行后面
[root@m01 ~]# sed -r '4r a.txt' A.txt
111111
222222666
55555lol55555
ll66666ll5555
111
222
444
444
555
666
777
222333ppp5555
LLAAALL

将A.txt的文件内容一到三行写入/tmp/a.conf文件中
[root@m01 ~]# sed -r '1,3w /tmp/a.conf' A.txt
111111
222222666
55555lol55555
ll66666ll5555
222333ppp5555
LLAAALL
[root@m01 ~]# cat /tmp/a.conf 
111111
222222666
55555lol55555

=======================================================================================================================
[root@svr7 ~]# cat d.txt
hello
link
ok
wo
111
222

单个字符串替换
[root@svr7 ~]# sed -r 'y/elo/XYZ/' d.txt
hXYYZ
Yink
Zk
wZ
111
222

将A.txt文件1到3行中lol字符串替换成LOL
[root@m01 ~]# sed -r '1,3s/lol/LOL/g' A.txt 
111111
222222666
55555LOL55555
ll66666ll5555
222333ppp5555
LLAAALL

q命令退出,q不指定行数,默认为1
[root@m01 ~]# sed -r '1,3{s/lol/LOL/g;q}' A.txt 
111111

指定行数1-3行,运行到第3行退出
[root@m01 ~]# sed -r '1,3{s/lol/LOL/g;3q}' A.txt 
111111
222222666
55555LOL55555

模式空间与保持空间

  • 模式空间:
    如你所知,模式空间用于 sed 执行的正常流程中。该空间 sed 内置的一个缓冲区,用来存放、修改从输入文件读取的内容。
  • 保持空间:
    保持空间是另外一个缓冲区,用来存放临时数据。Sed 可以在保持空间和模式空间交换数据,但是不能在保持空间上执行普通的 sed 命令。

我们已经讨论过,每次循环读取数据过程中,模式空间的内容都会被清空,然而保持空间的内容则保持不变,不会在循环中被删除。

模式空间与保持空间的操作命令

x:命令x(exchange) 用于交换模式空间和保持空间的内容

h:模式空间复制/覆盖到保持空间
H:模式空间追加到保持空间

g:保持空间复制/覆盖到模式空间
G:保持空间追加到模式空间

n:读取下一行到/覆盖到模式空间
N:将下一行添加到模式空间

d:删除pattern space中的所有行,并读入下一新行到pattern space中

案例

将文件的输出结果倒过来输出

方式一:
[root@m01 ~]# cat test.txt
111
222
333

[root@m01 ~]# tac test.txt
333
222
111
方式二:
思路:
1、读取文件第一行内容到模式空间,进行的操作如下  
将模式空间内容覆盖到保持空间
删除模式空间内容
   
2、读取文件第二行内容到模式空间,进行的操作如下  
将保持内容追加到模式空间
将模式空间内容覆盖到保持空间
删除模式空间内容 

3、读取文件第三行内容到模式空间,进行的操作如下  
将保持空间内容追加到模式空间


[root@m01 ~]# sed -r '1h;1d;2G;2h;2d;3G' test.txt
333
222
111

三剑客之awk命令

awk介绍

注意awk需要用' '!!!

awk
是一种编程语言,用于在linux/unix下对文本和数据进行处理。数据可以来自标准输入、一个或多个文件,或其它命令的输出。它支持用户自定义函数和动态正则表达式等先进功能,是linux/unix下的一个强大编程工具。它在命令行中使用,但更多是作为脚本来使用。
awk的处理文本和数据的方式是这样的,它逐行扫描文件,从第一行到最后一行,寻找匹配的特定模式的行,并在这些行上进行你想要的操作。如果没有指定处理动作,则把匹配的行显示到标准输出(屏幕),如果没有指定模式,则所有被操作所指定的行都被处理。

awk格式如下

awk 选项 'BEGIN{}模式匹配{}END{}' 文件路径

- BEGIN处理所有行之前处理的代码;END处理所有行之后处理的代码;匹配模式,把每一行的内容读入内存运行
=======================================================================================================================
命令 | 选项 'BEGIN{}模式匹配{}END{}'

awk运行原理

[root@m01 ~]# head -10 /etc/passwd | awk 'BEGIN{count=0;FS=":"}{print $0;count++}END{print count}' 
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
operator:x:11:0:operator:/root:/sbin/nologin
10

1.运行行前处理代码BEGIN{count=0;FS=":"}

2.再运行行处理
(1)读一行内存中,然后awk生成一系列内置变量
$0:表示一整行内容
$1:切分出的第一段内容
$2:切分出的第二段内容
NR:行号
NF:段数
FS:输入分隔符,即按照什么符号来切分每一行内容
OFS:输出分隔符,即按照什么符号来连接输出结果		# 如下所示:{print $1,$3;count++}
(2)运行行处理代码:{print $0;count++}
(3)循环往复,直到所有行都处理完毕

3.最后运行:行后处理
END{print count}

[root@m01 ~]# head -10 /etc/passwd | awk 'BEGIN{count=0;FS=":"}{print $1,$3;count++}END{print count}' 
root 0
bin 1
daemon 2
adm 3
lp 4
sync 5
shutdown 6
halt 7
mail 8
operator 11
10

[root@m01 ~]# head -10 /etc/passwd | awk -F: '{print NR,$0}'
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 operator:x:11:0:operator:/root:/sbin/nologin

[root@m01 ~]# head -10 /etc/passwd | awk -F: '{print NF,$0}'
7 root:x:0:0:root:/root:/bin/bash
7 bin:x:1:1:bin:/bin:/sbin/nologin
7 daemon:x:2:2:daemon:/sbin:/sbin/nologin
7 adm:x:3:4:adm:/var/adm:/sbin/nologin
7 lp:x:4:7:lp:/var/spool/lpd:/sbin/nologin
7 sync:x:5:0:sync:/sbin:/bin/sync
7 shutdown:x:6:0:shutdown:/sbin:/sbin/shutdown
7 halt:x:7:0:halt:/sbin:/sbin/halt
7 mail:x:8:12:mail:/var/spool/mail:/sbin/nologin
7 operator:x:11:0:operator:/root:/sbin/nologin

$NF以:进行分隔,取最后一段内容
[root@m01 ~]# head -10 /etc/passwd | awk -F: '{print $NF}'
/bin/bash
/sbin/nologin
/sbin/nologin
/sbin/nologin
/sbin/nologin
/bin/sync
/sbin/shutdown
/sbin/halt
/sbin/nologin
/sbin/nologin

[root@m01 ~]# vim a.awk
{print $1,$NF }
[root@m01 ~]# awk -F: -f a.awk /etc/passwd
root /bin/bash
bin /sbin/nologin
daemon /sbin/nologin
adm /sbin/nologin
lp /sbin/nologin
sync /bin/sync

记录与字段相关内部变量

$0:	保存当前行的内容				# awk -F: '{print $0}' /etc/passwd
NR:	记录号,每处理完一条记录,NR值加1  # awk -F: '{print NR, $0}' /etc/passwd
NF:	保存记录的字段数,$1,$2...$100	# awk -F: '{print $0,NF}' /etc/passwd
FS:	输入字段分隔符,默认空格		# awk -F: '/alice/{print $1, $3}' /etc/passwd
								# awk -F'[ :\t]' '{print $1,$2,$3}' /etc/passwd	
								# awk 'BEGIN{FS=":"} {print $1,$3}' /etc/passwd
OFS:输出字段分隔符		# awk -F: '/root/{print $1,$2,$3,$4}' /etc/passwd
					# awk -F: 'BEGIN{OFS="+++"} /^root/{print $1,$2,$3,$4}' /etc/passwd
    			   # awk  'BEGIN{OFS="-";FS=":"}/root/{print NR,$0,NF}' /etc/passwd

比较表达式

比较表达式指的是使用关系运算符来比较数字以及字符串,只有当条件为真,才执行指定的动作

关系运算符
运算符			  	含义						   	  示例
<				    小于							  x<y
<=			    	小于或等于					  x<=y
==			 		等于							  x==y
!=					不等于					      x!=y
>=					大于等于						  x>=y
>					大于							  x>y
~					正则表达式匹配				  x~/y/
!~					正则表达式不匹配			 	  x!~/y/

逻辑运算和复合模式

&&			逻辑与			a&&b
||			逻辑或			a||b
!			逻辑非			!a

格式化输出

================print函数===================
方式一:
[root@m01 ~]# awk -F: 'BEGIN{OFS="---"}{print "行号:"NR,"用户名:"$1}' /etc/passwd
行号:1---用户名:root
行号:2---用户名:bin
行号:3---用户名:daemon
行号:4---用户名:adm
行号:5---用户名:lp

================printf函数===================
方式二:
[root@m01 ~]# awk -F: 'BEGIN{OFS="---"}{print "行号:"NR,"用户名:"$1}' /etc/passwd
行号:1---用户名:root
行号:2---用户名:bin
行号:3---用户名:daemon
行号:4---用户名:adm
行号:5---用户名:lp


%s 字符类型
%d 数值类型
占15格的字符串
- 表示左对齐,默认是右对齐
printf默认不会在行尾自动换行,加\n

awk的使用案例

- 行定位
定位到第一行
[root@m01 ~]# awk -F: 'NR==1{print NR,$1}' a.txt
1 root

定位到一到三行
[root@m01 ~]# awk -F: 'NR>=1 && NR<=3{print NR,$1}' a.txt
1 root
2 bin
3 daemon

定位第一行和第三行
[root@m01 ~]# awk -F: 'NR==1 || NR==3{print NR,$1}' a.txt
1 root
3 daemon

- 正则定位
[root@m01 ~]# awk -F: '/root/{print NR,$0}' a.txt
1 root:x:0:0:root:/root:/bin/bash
10 operator:x:11:0:operator:/root:/sbin/nologin

[root@m01 ~]# awk -F: '/^root/{print NR,$0}' a.txt
1 root:x:0:0:root:/root:/bin/bash

匹配分隔开的第一段中以root开头的行
[root@m01 ~]# awk -F: '$1 ~ /^root/{print NR,$0}' a.txt
1 root:x:0:0:root:/root:/bin/bash

正则取反匹配
[root@m01 ~]# awk -F: '!($1 ~ /^root/){print NR,$0}' a.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

[root@m01 ~]# awk -F: '!(NR>=3){print NR,$1}' a.txt
1 root
2 bin

=======================================================================================================================
[root@m01 ~]# cat A.txt 
......root
.........
.........
nana.....
.........
.....root
.........
.........
.........
.........
..nana...
........

正则范围匹配
[root@m01 ~]# awk -F: '/root/,/nana/{print NR,$0}' A.txt
1 ......root
2 .........
3 .........
4 nana.....
6 .....root
7 .........
8 .........
9 .........
10 .........
11 ..nana...

=======================================================================================================================
[root@m01 ~]# cat A.txt 
......root
.........
.........
nana.....
.........
.....root
.........
.........
.........
.........
.........
........

匹配规则默认以开头进行匹配,如果结尾不符合匹配规则,那么默认会打印所有行
[root@m01 ~]# awk -F: '/root/,/nana/{print NR,$0}' A.txt
1 ......root
2 .........
3 .........
4 nana.....
6 .....root
7 .........
8 .........
9 .........
10 .........
11 .........
12 ........

=======================================================================================================================
[root@m01 ~]# cat A.txt 
......root
.........
.........
nana.....
nana.....
.....root
nana.....
.........
nana.....
.........
.........
.........

匹配第四行到第七行之间,包含nana的行
[root@m01 ~]# awk 'NR>=4 && NR <=7 && /nana/{print NR,$0}' A.txt
4 nana.....
5 nana.....
7 nana.....

正则匹配第一段以root结尾的行
[root@m01 ~]# awk -F: '$1 ~ /root$/{print $0}' A.txt
......root
.....root

正则匹配第一段不是以以root结尾的行
[root@m01 ~]# awk -F: '$1 !~ /root$/{print $0}' A.txt
.........
.........
nana.....
nana.....
nana.....
.........
nana.....
.........
.........
.........

=======================================================================================================================
- 算数运算
[root@m01 ~]# cat c.txt 
# 名字:工资:年龄
nana:18:16
dada:19:18
lala:20:26

打印年薪大于120的名字
[root@m01 ~]# awk -F: '$2*12>120 {print NR,$1}' c.txt 
1 nana
2 dada
3 lala

打印出偶数行
[root@m01 ~]# awk -F: 'NR %2 ==0{print NR,$1}' c.txt 
2 dada

打印出奇数行
[root@m01 ~]# awk -F: 'NR %2 !=0{print NR,$1}' c.txt 
1 nana
3 lala

注意:行号跟正则不能混合使用,如下所示

[root@m01 ~]# awk -F: ‘NR>=3,/nana/{print NR,$1}’ A.txt
3 …
4 nana…
5 nana…
6 …root
7 nana…
8 …
9 nana…
10 …
11 …
12 …

awk流程控制

awk的流程控制if判断,while循环完全是可以用shell语法实现的,这个知识点了解即可。

- awk语法的流程控制之if判断+格式化输出
[root@m01 ~]# awk -F: 'BEGIN{x=0;y=0;z=0}{if ($3 == 0){x++} else if ($3 >=1 && $3 <= 999){y++} else {z++}}END{printf "管理员数:%s 系统用户数:%s 普通用户数:%s\n",x,y,z}' /etc/passwd
管理员数:1 系统用户数:21 普通用户数:1

- shell语法实现的if判断+格式化输出
vim a.sh
#!/bin/bash

user=`awk -F: '{print $3}' /etc/passwd`
x=0
y=0
z=0

for i in $user
do
        if [ $i -eq 0 ];then
                let x++
        elif [ $i -ge 1 -a $i -le 999 ];then
                let y++
        else
                let z++
        fi
done

printf "管理员数:%s 系统用户数:%s 普通用户:%s\n" $x $y $z

[root@m01 ~]# bash a.sh
管理员数:1 系统用户数:21 普通用户:1

=======================================================================================================================
使用awk语法的while循环将a.txt的文件内容循环打印3次。
[root@m01 ~]# awk '{n=1;while (n<=3){print $0;n++}}' a.txt
root:x:0:0:root:/root:/bin/bash
root:x:0:0:root:/root:/bin/bash
root:x:0:0:root:/root:/bin/bash
bin:x:1:1:bin:/bin:/sbin/nologin
bin:x:1:1:bin:/bin:/sbin/nologin
bin:x:1:1:bin:/bin:/sbin/nologin

使用awk语法的for循环将a.txt的文件内容循环打印3次。
[root@m01 ~]# awk '{for (n=1;n<=3;n++){print $0}}' a.txt
root:x:0:0:root:/root:/bin/bash
root:x:0:0:root:/root:/bin/bash
root:x:0:0:root:/root:/bin/bash
bin:x:1:1:bin:/bin:/sbin/nologin
bin:x:1:1:bin:/bin:/sbin/nologin
bin:x:1:1:bin:/bin:/sbin/nologin

使用awk语法的for循环将a.txt的文件内容定义成普通数组遍历取值。
[root@m01 ~]# awk -F: 'BEGIN{i=0}{username[i]=$1;i++}END{for (x=0;x<i;x++){print username[x]}}' a.txt
root
bin
daemon
adm
lp

[root@m01 ~]# awk -F: 'BEGIN{i=0}{username[i]=$1;i++}END{for (x in username){print username[x]}}' a.txt
abrt
lp
sshd
sync

使用awk语法的for循环将a.txt的文件内容定义成关联数组遍历取值。
[root@m01 ~]# awk -F: '{username[$1]=$3;i++}END{for (k in username){print k}}' a.txt
rpc
sshd
systemd-network
shutdown
bin

使用awk语法取出a.txt文件中4个字符的用户名
[root@m01 ~]# awk -F: '$1 ~ /^....$/{print $0}' a.txt
root:x:0:0:root:/root:/bin/bash
sync:x:5:0:sync:/sbin:/bin/sync
halt:x:7:0:halt:/sbin:/sbin/halt
mail:x:8:12:mail:/var/spool/mail:/sbin/nologin
dbus:x:81:81:System message bus:/:/sbin/nologin
abrt:x:173:173::/etc/abrt:/sbin/nologin
sshd:x:74:74:Privilege-separated SSH:/var/empty/sshd:/sbin/nologin

三剑客综合练习题整理

1、找出/proc/meminfo文件中以s开头的行,至少用三种方式忽略大小写
grep -E '^[sS]' /proc/meminfo
sed -rn '/^[sS]/p' /proc/meminfo
awk '/^s|^S/{print $0}' /proc/meminfo

2、找出/etc/init.d/function文件下包含小括号的行
grep -E '(\(.*\))' a.txt
# ()组字符

3、输出指定目录的基名
pwd | awk -F/ '{print $NF}'

4、找出网卡信息中包含的数字
ip a | grep -Eo '[0-9]+'
# 选项o,只显示匹配的内容

5、找出/etc/passwd下每种解析器的用户个数
方法一:
awk -F: '{print $NF}' /etc/passwd | sort | uniq -c
# sort排序,uniq -c 显示重复的次数	

方法二:
#!/bin/bash

# 定义一个关联数组
declare -A arrary

while read line
do
	# res=/etc/passwd文件中以:分隔开每一行的最后一个值
    res=`echo $line |awk -F: '{print $NF}'`
    let arrary[$res]++
    # arrary["/sbin/nologin"]=19 
    # arrary["/bin/sync"]=1 
    # arrary["/bin/bash"]=1 
    # arrary["/sbin/shutdown"]=1 
    # arrary["/sbin/halt"]=1 
done < /etc/passwd

# ${!arrary[*]}遍历出key值;${arrary[$i]}遍历出value值
for i in ${!arrary[*]}
do
    echo $i:${arrary[$i]}
done

方法三:
awk -F: '{num[$NF]++}END{for (i in num){printf "%-15s : %s\n",i,num[i]}}' /etc/passwd

6、过滤出网卡中的ip
ip a | grep -Eo '([0-9]{1,3}\.){3}[0-9]{1,3}'

7、搜索/etc目录下,所有的.html或.php文件中main函数出现的次数
find /etc -name "*.html" -o -name "*.php" -exec grep -R "main" {} \;
# -R递归

8、过滤php.ini中注释的行和空行
grep -vE '^$|^#' /etc/php.ini

9、找出文件中至少有一个空格的行
grep -E '\ +' /etc/passwd

10、过滤文件中以#开头的行,后面至少有一个空格
grep -E '^#\ +' /etc/fstab

11、查询出/etc目录中包含多少个root
grep -ERo 'root' /etc/| wc -l
# -R递归,-o只显示匹配的内容

12、查询出所有的qq邮箱
grep -Er "[0-9a-zA-Z-_\.]+\@qq\.com" wyr.txt
# -r递归

13、查询系统日志中所有的error
grep -iE 'error' /var/log/message
# -i忽略大小写

14、删除某文件中以s开头的行的最后一个词
grep -E "^s" a.txt | sed -r 's/[0-9a-zA-Z]+$//g'

15、删除一个文件中的所有数字
sed -r 's/[0-9]+//g' a.txt

16、显示奇数行
awk -F: 'NR %2 !=0{print NR,$0}' /etc/passwd 
awk '{if (NR%2){print $0}}' /etc/passwd
# if判断%2有余数为证,条件成立,判断成立

17、删除passwd文件中以bin开头的行到nobody开头的行
sed -r '/^bin/,/^nobody/d' /etc/passwd

18、从指定行开始,每隔两行显示一次
awk -F: '{if(NR>3){num=(NR-3)%2; if(num){print $0}}}' /etc/passwd

19、每隔5行打印一个空行
awk -F: '{print $0;num=NR%5;if(num==0){print ""}}' /etc/passwd

20、将文件中1到5行中aaa替换成AAA
sed -r '1,5s/aaa/AAA/g' /etc/passwd

21、显示用户id为奇数的行
awk -F: '{if($3%2){print $0}}' /etc/passwd

22、显示系统普通用户,并打印系统用户名和id
awk -F: '{if($3>=1000){print $1,$3}}' /etc/passwd

23、统计nginx日志中访问量(ip维度计算)
grep -Ec '([0-9]{1,3}\.){3}[0-9]{1,3}' /var/log/nginx/access.log
# -c 如果匹配成功,则将匹配到的行数打印出来

24、实时打印nginx的访问ip
tail -f /var/log/nginx/access.log | grep -oE '([0-9]{1,3}\.){3}[0-9]{1,3}'
# -o 只显示匹配的内容

25、统计php.ini中每个词的个数
grep -Eow '[0-9a-zA-Z]+' a.txt | awk '{words[$1]++}END{for (i in words){print i,words[i]}}'
# -w 匹配单词	 -o 只显示匹配的内容
# words[$1]++定义为一个关联数组;words默认取得是key值,words[i]取得是value值

26、统计1小时内访问nginx次数超过10次的ip
#!/bin/bash

NGINX_LOG=/var/log/nginx/access.log
# 1970年到当前的时间,单位s(秒)
TIME=`date +%s`
# 距离1970年,一个小时之前的时间
DATE=`echo $TIME - 3600 | bc`
# 定义一个关联数组
declare -A IP
while read line
do
	# 日志记录的时间,转换成距离1970年的时间,单位s(秒)
	timestamp=`echo $line | grep -oE '[0-9]{4}.*T[0-9]{2}:[0-9]{2}:[0-9]{2}'`
	timestamp=`date -d "$timestamp" +%s`
	# 如果日志记录的时间在一个小时以内,那么符合判断条件
	if (( $TIME >= $timestamp && $DATE <= $timestamp ));then
		# 定义一个ip地址变量
		ip=`echo $line| grep -oE '([0-9]{1,3}\.){3}[0-9]{1,3}'`
		# 判断数组IP的value值存不存在,wc -L统计每一个value的长度
		number=`echo ${IP["$ip"]} | wc -L`
		# 初始化一个ip计数为0,开始计数
		[ $number -eq 0 ] && IP["$ip"]=0
		num=${IP["$ip"]}
		# 生成关联数组IP["$ip"]=次数
		IP["$ip"]=`echo "$num + 1" | bc`
	fi
done < $NGINX_LOG

# 遍历ip地址(key值)
for i in ${!IP[*]}
do
	# 如果IP["$ip"]的value值大于10,那么打印ip地址
	if (( ${IP[$i]} >= 10 ));then
		echo $i
	fi
done

27、找出nginx访问的峰值(按照大于10次来计算),按每个小时计算
#!/bin/bash

NGINX_LOG=/var/log/nginx/access.log

declare -A IP

while read line
do
	# 日志记录的时间,记录时间格式例如"2021062910",哪个时间段,nginx被访问的次数最多
	timestamp=`echo $line | grep -oE '[0-9]{4}.*T[0-9]{2}:[0-9]{2}:[0-9]{2}'`
	timestamp=`date -d "$timestamp" +%Y%m%d%H`

	# 判断数组IP的value值存不存在,wc -L统计每一个value的长度
	number=`echo ${IP["$timestamp"]} | wc -L`
	# 初始化一个ip计数为0,开始计数
	[ $number -eq 0 ] && IP["$timestamp"]=0
	# 数组通过key值取value,value值为访问次数
	num=${IP["$timestamp"]}
	# 生成关联数组IP["时间"]=次数
	IP["$timestamp"]=`echo "$num + 1" | bc`
done < $NGINX_LOG

# 遍历时间(key值)
for i in ${!IP[*]}
do
	# 如果IP["$ip"]的value值大于10,那么打印Nginx被访问的时间,Nginx被访问的次数
	if (( ${IP[$i]} >= 10 ));then
		echo "$i ${IP[$i]}"
	fi
done

28、统计访问nginx前10的ip
grep -oE '([0-9]{1,3}\.){3}[0-9]{1,3}' /var/log/nginx/access.log | sort | uniq -c | sort -r | head 
# sort -r 倒叙
  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值