剑客之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 倒叙