Linux 文本处理三剑客

一、grep:文本过滤工具

grep 语法格式:

grep [OPTIONS] PATTERN   [FIFE]
grep   参数     匹配模式  查找的文件
参数选项 解释说明
-v 显示不匹配的行,或者说排除某些行,显示不包含匹配文本的所有行
-n 显示匹配行及行号
-i 不区分大小写(只适用于单字符),默认是区分大小写的
-c 只统计匹配的行数,注意不是匹配的次数
-E 使用扩展的 egrep 命令
--color=auto 为 grep 过滤的匹配字符串添加颜色
-w 只匹配过滤的单词,单词的两边必须是非字符符号(即不能是字母数字或下划线)
-o 只输出匹配的内容

有文本如下(test.txt)

test
dongye
oldboy

linux
ubuntu
centos

LOL
dota2
i like playing dota2

1.1 -v 参数实践

# 过滤不包含oldboy字符串的行,注意被过滤的字符串,尽可能使用双引号
grep -v "dota2" test.txt

>>>
test
dongye
oldboy

linux
ubuntu
centos

LOL

提示: grep 的 -v 参数的作用是排除,默认是以行为单位排除包含参数后面所接内容的某些行

1.2 -n 参数实践

# 输出包含 oldboy 字符串的行,并显示行号
grep -n "dota2" test.txt

>>>
1:dota2
2:i like playing dota2

提示: -n 参数会对 grep 命令找到的内容在开头加上对应的行号

1.3 -i 不区分大小写参数实践

grep "lol" test.txt

>>>
找不到值
grep -i "lol" test.txt
>>>
LOL

1.4 -E 和 --color 的参数实践

# 默认不支持多条件匹配
grep "like|dota2" test.txt

# 多条件匹配,加 -E
grep -E "like|dota2" test.txt   

>>>
dota2
i like playing dota2

# 加颜色
grep -Ei --color=auto "like|dota2" test.txt

1.5 -c 参数实践

grep "dota2" test.txt

>>>
dota2
i like playing dota2

# 只想计算匹配的字符串的数量
grep -c "dota2" test.txt

>>>
2

1.6 -o 参数实践

# 注意这里没有 双引号
grep -o dota2 test.txt

>>>
dota2
dota2

1.7 -w 参数实践

grep -w "like" text.txt

# 结果为空

1.8 grep 常用

# 查找指定进程
ps -ef | grep nginx

# 查找指定进程并统计数量
ps -ef | grep -c nginx

# 从文件中查找关键字
grep 关键字 test.txt

# 从文件中查找关键字并输出它的行号
grep -n 关键字 text.txt

# 从多个文件中查找关键字
grep 关键字 test1.txt test2.txt test3.txt

# 从文件中查找关键字后,再从结果中找到指定关键字
cat text.txt | grep -v 不要的关键字 | grep -w 要的单词
ps -ef | grep dub-finance | grep -v grep | awk '{print $2}' | xargs kill -9

# 找出文件中的空白行
grep -n "^$" test.txt

# 显示当前目录下面以 .txt 结尾的文件中的所有包含每个字符串至少有4个连续小写字符的字符串的行
grep -n '[a-z]\{4\}' *.txt

二、sed:字符流编辑器

语法格式

sed [选项] [sed内置命令字符] [输入文件]

说明:

  1. sed以及后面的选项、命令和输入文件,每个元素之间都至少要有一个空格。
  2. 【sed内置命令字符】,既可以是单个命令,也可以是多个命令参数的组合
  3. 【输入文件】为sed 需要处理的文件,这是可选项,sed 还能够从标准输入如管道中获取输入

2.1 选项、内置命令说明

参数选项

参数选项 解释说明
-n 取消默认的sed的输出,常与sed内置命令的p连用
-i 直接修改文件内容,而不是输出到终端。如果不使用 -i 选项,则sed只是修改内存中的数据,并不会影响磁盘上的文件

sed内置命令字符

sed的内置命令字符 解释说明
a 全拼 append,表示追加文本,在指定行后添加一行或多行文本
d 全拼 delete,表示删除匹配行的文本
i 全拼 insert,表示插入文本,在指定行前添加一行或多行文本
p 全拼 print,表示打印匹配行的内容,通常 p 会与选项 -n 一起使用
s/regexp/replacement 匹配 regexp 部分的内容,用 replacement 替换 regexp 匹配的内容,regexp部分可以使用正则表达式,在 replacement 部分可以使用特殊字符 & 和 \1-\9等匹配 regexp 部分的部分内容。在实战场景中,s/regexp/replacement/g 结尾常与g匹配做全局的替换

2.2 示例文本

先准备一个文本 tex.txt

101,oldboy,CEO
102,zhangyao,CTO
103,Alex,COO
104,yy,CFO
105,feixue,CTO

2.3 在文本指定行后追加文本

sed "2a 106,dandan,CSO" test.txt

>>>
101,oldboy,CEO
102,zhangyao,CTO
106,dandan,CSO
103,Alex,COO
104,yy,CFO
105,feixue,CTO

2a 106,dandan,CSO的意思:

  1. 2 表示对第 2 行进行操作,其他的行忽略
  2. a 表示追加,2a 即在第 2 行后追加文本
  3. 2a 后面加上空格,然后接着输入想要追加的文本内容(106,dandan,CSO`)即可

2.4 在文本指定的行前面插入文本

sed "2i 106,dandan,CSO" text.txt

>>>
101,oldboy,CEO
106,dandan,CSO
102,zhangyao,CTO
103,Alex,COO
104,yy,CFO
105,feixue,CTO

2i 106,dandan,CSO的意思:

  1. 2 表示对第 2 行进行操作,其他的行可忽略
  2. i 代表插入的意思,2i 表示在第2行即当前行插入文本,即插入到第二行
  3. 2i 后面加上空格,然后跟上要插入的文本(106,dandan,CSO),最后接上要处理的文件 text.txt

2.5 在文件指定行后追加多行文本

sed "2a 106,dandan,CSO\n107,bingbing,CCO" text.txt

>>>
101,oldboy,CEO
102,zhangyao,CTO
106,dandan,CSO
107,bingbing,CCO
103,Alex,COO
104,yy,CFO
105,feixue,CTO

2.6 删除文件中一行指定的文本

sed "2d" text.txt

>>>
101,oldboy,CEO
103,Alex,COO
104,yy,CFO
105,feixue,CTO

2.7 删除文件中指定的多行文本

sed "2,5d" text.txt
# 表示删除 2-5 行,所以结果只剩下一行
>>>
101,oldboy,CEO

2.8 使用sed命令替换文本内容

sed "s#zhangyao#dandan#g" text.txt

>>>
101,oldboy,CEO
102,dandan,CTO
103,Alex,COO
104,yy,CFO
105,feixue,CTO

2.9 打印输出文件的指定行的内容

sed "2p" text.txt

# 这里使用了 sed 内置命令 p 来实现查询功能,并结合数字地址指定查询第2行的内容,但是我们会发现结果不只是输出第2行,文件的其他内容也显示出来了,这是因为 sed 命令有一个默认输出的功能.
>>>
101,oldboy,CEO
102,zhangyao,CTO
103,Alex,COO
104,yy,CFO
105,feixue,CTO


sed -n "2p" text.txt

# 为了解决上面命令显示多余内容的问题,使用选项 -n 取消默认输出,只输出匹配行的文本,因此大家只需要记住使用命令 p 必用选项 -n
>>>
102,zhangyao,CTO


sed -n "2,4p" text.txt
# 输出 2-4 行
>>>
102,zhangyao,CTO
103,Alex,COO
104,yy,CFO

2.10 -i 选项

	这个选项的作用是能够实际修改文件的内容,前面几个例子操作完命令之后,文件的内容并没有发生变化,这是因为 sed 命令默认操作的是内存中的数据,如果想要真正地修改文件的内容,就需要使用选项 `-i`将修改写到磁盘文件上。

2.11 N 内置命令

有文件如下

stu10309
7f754wdw
stu10123
faioj322
stu12452
fasdassa
...

现在要把格式变成

stu10309=7f754wdw
stu10123=faioj322
stu12452=fasdassa

可用以下方法实现

sed "N;s#\n#=#g" text.txt
	sed 内置命令 N 的作用:不会清空模式空间的内容,并且从输入文件中读取下一行数据,追加到模式空间中,两行数据以换行符 \n 连接。

	第一行是 `stu10309` 存入模式控件,碰到命令 `N`,读取第二行 `7f754wdw`,此时模式空间的内容为 `stu10309\n7f754wdw`;然后执行 `s#\n#=#g` 将 `\n`替换为 `=`,即为 `stu10312=`7f754wdw`,输出到屏幕中,第一个循环结束;后面的循环和前面的思路一样,直到文件结束。

三、awk 基础入门

	不仅是Linux系统中的一个命令,而且还是一种编程语言。是Linux系统最强大的文本处理工具,没有之一。

3.1 参数选项及说明

awk 命令的常用功能 简要例子说明
指定分隔符显示某几列 awk -F "GET|HTTP" '{print $2}' test.log 直接取出显示出日志文件的 url 这一列
通过正则表达式取出你想要的的内容 awk '$6~/Failed/{print $11}' /var/log/secure 分析生产环境中的日志找出谁在破解用户的密码
显示出某个范围内的内容 awk 'NR20,NR30' filename 显示文件的20到30行内容
通过awk进行统计计算 awk '{sum+=$0}END{print sum}' ett.txt 计算总和
awk数组计算与去重 awk '{array[$1]++}END{for(key in array)print key,array[key]}' access.log 对日志进行统计与计数
awk  [option]  'pattern{action}' file ...
       参数         '条件{动作}'    文件 ... 

参数选项及说明

参数选项 解释说明
-F 指定字段分隔符
-v 定义或修改一个 awk 内部的变量

3.2 示例文本

root:x:0:0:root:/root:/bin/bash
bin:x:1:1:bin:/bin:/sbin/nologin
daemon:x:2:2:daemon:/sbin:/sbin/mologin
adm:x:3:4:adm:/var/adm:/sbin/lologin
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
uucp:x:10:14:uucp:/var/spool/uucp:/sbin/nologin

3.3 显示文件中的第5行

cat -n test.txt   # 先打印内容并在每行内容的开头显示行号

awk 'NR==5' test.txt
	首先NR 在awk中表示行号(记录号),NR==5表示行号等于5的行。这里需要注意的是必须使用两个等号,在awk中两个等号表示 ”等于“,一个等号表示赋值,即向一个变量里面放置内容。

注意:awk后面所接的内容要用单引号

显示一部分行的内容,例如显示 2-6 行

awk 'NR==2,NR==6' test.txt

3.4 用 awk 实现给文件每行的内容之前加上行号

awk '{print NR,$0}' test.txt

这里的NR还是表示行号,$0 表示一整行的内容(一行的内容)。

3.5 显示第 2 行到 第 6 行,并打印行号

awk 'NR==2,NR==6 {print NR,$0}' test.txt

3.6 显示文件的第 1 列、第 3 列和最后一列

awk -F ":" '{print $1,$3,$NF}' test.txt
	这里我们使用了 awk 的 -F参数。-F表示指定一个`分隔符`来切割每一行的内容,-F后面可用单双引号或不加引号,但是,建议加双引号。

	`$1`表示根据分隔符分割的第一列,`$2`表示根据分隔符分割的第二列,以此类推。

	`$0`表示整行。`$NF`表示最后一列。

3.7 把文件中的 /sbin/nologin 替换为 /bin/bash

awk '{gsub("/sbin/nologin","/bin/bash",$0);print $0}' test.txt

3.8 生产案例1:取出 eh0 网卡对应的ip地址

ifconfig eth0

>>>
eho Link encap:Ethernet Hwaddr 00:0C:29:93:49:99
inet addr:10.0.0.8 Bcast:10.0.0.255 Mask:255.255.255.0
...

​ 取出的方式

ifconfig eth0|awk -F "(addr:)|(  Bcast:)" 'NR==2{print $2}'
>>>
10.0.0.8

​ 我们的目标是取得ip,本例是10.0.0.8,ip的左边是 addr:,右边是 Bcast:。所以两边都是分隔符,就可以取到我们想要取到的值。(这里需要注意-F 指定多分割符的写法

​ 还有一个简单的方法

ifconfig eth0|awk -F "[ :]+" 'NR==2{print $4}'

​ 结合起来,-F "[ :]+"就是以单个或连续的空格或冒号或者它们的组合为分隔符。最后就可以获得我们想要的ip地址。

3.9 面试题--统计域名访问次数

测试数据如下:

http://www.etiantian.org/index.html
http://www.etiantian.org/1.html
http://post.etiantian.org/index.html
http://mp3.etiantian.org/index.html
http://www.etiantian.org/3.html
http://post.etiantian.org/2.html

3.9.1 方案1

(1)取出每行中的域名

awk -F '/' '{print $3}' test.txt

>>>
www.etiantian.org
www.etiantian.org
post.etiantian.org
mp3.etiantian.org
www.etiantian.org
post.etiantian.org

(2)排序(让相同的域名相邻)

awk -F '/' '{print $3}' test.txt|sort

(3)去重计数

awk -F '/' '{print $3}' test.txt|sort|uniq -c

3.9.2 方案2(awk数组方案)

(1)取出域名

awk -F '/' '{print $3}' test.txt

(2)创建一个 awk 数组,然后把第二列(域名)作为数组的下标,再通过类似于 i++ 的形式来计算域名重复的次数

awk -F '/' '{hotel[$3]}' test.txt  # 创建 awk 的hotel 数组
awk -F '/' '{hotel[$3];print $3}' test.txt  #创建 awk 的hotel 数组,并通过 print 输出元素名字(房间号码),注意,这里没输出数组,所以看到的还是第一阶段的内容

>>>
awk -F '/' '{print $3}' test.txt

(3)开始统计

awk -F '/' '{hotel[$3]++;print $3,hotel[$3]}' test.txt

>>>
www.etiantian.org 1
www.etiantian.org 2
post.etiantian.org 1
mp3.etiantian.org 1
www.etiantian.org 3
post.etiantian.org 2

(4)输出最终结果

上面的命令详细地显示了 awk 统计的过程。如果想要获得最终结果该怎么办呢?通过END模式来输出最终结果。

awk -F '/' '{array[$3]++}END{
print "www.etiantain.org",array["www.etiantian.org"];
print "post.etiantian.org",array["post.etiantian.org"];
print "mp3.etiantian.org",array["mp3.etiantian.org"];
}' test.txt

awk数组提供了自己独有的方法来完成它——一个专用的循环:

awk -F '/' '{hotel[$3]++}END{for(domain in hotel)print damain,hotel[domain]}' test.txt

>>>
mp3.etiantian.org 1
post.etiantian.org 2
www.etiantian.org 3

posted @ 2021-02-26 01:12  dongye95  阅读(218)  评论(0编辑  收藏  举报