Linux文本三剑客Grep、Sed、Awk 常用案例

1,698 阅读5分钟

持续创作,加速成长!这是我参与「掘金日新计划 · 10 月更文挑战」的第2天,点击查看活动详情

买了一台个人服务器,跑了一个应用:

  • 应用起不来了,是什么问题? 看日志?看配置有没有问题?
  • 想统计下现在应用的访问ip有多少,有没有异常ip?

怎么检索这些日志,或者统计日志?

  • 如果是在公司,阿里云提供了SLS日志服务,可以帮助我们很好的做这件事,好用确实真的好用,各种检索语法,各种统计函数,还可以使用SQL进行统计,只是价格有点贵...

  • 成本再低一点的方式,自己搭建ELK服务,也可以方便的检索日志,不过ELK比较吃内存,一般要单独准备机器,也需要一点预算... 比SLS会便宜点

个人开发者,只有一台小型的服务器,跑个应用程序机器就快跑不动了,也不想增加额外开支,遇到了问题,那就使用Linux自带的文本检索统计工具吧。

Linux自带的工具非常多,但是功能强大的文本处理有grep、sed、awk,也被称为文本三剑客;对于日志排查,或者处理配置文件都很有帮助。

其余的文本处理命令相对比较简单:

  • cat 直接输出文件的全部内容
  • less 查看文件的全部内容,同时可以搜索
  • tail 从尾部查看文件的内容
  • tail -f 查看文件内容,并且持续监控日志输出
  • head 查看文件头部内容
  • ...

接下来详细介绍这三个功能强大的文本工具:

Grep - 搜索目标内容

Grep说起来其实就专注做一件事情,匹配目标文本;使用正则表达式搜索目标内容。 可以对单个文件进行搜索,可以对目录进行搜索,可以对命令行中的管道输出进行搜索... 各种文本搜索。

语法

grep [OPTIONS] PATTERN [FILE...]

# grep -e等于egrep,支持正则搜索
grep [OPTIONS] -e PATTERN ... [FILE...]

PATTERN即要搜索的正则规则,OPTIOSN可以控制如何输出匹配到的内容。

常用选项介绍:

 -A<显示行数>:除了显示符合范本样式的那一列之外,并显示该行之后的内容。 After
 -B<显示行数>:除了显示符合样式的那一行之外,并显示该行之前的内容。 Before
 -C<显示行数>:除了显示符合样式的那一行之外,并显示该行之前后的内容。 Context
 -i   忽略字符大小写的差别。
 -c: 统计匹配的行数
 -n: 显示匹配的行号
 -o: 仅显示匹配到的字符串
 -q: 静默模式,不输出任何信息
 -s: 不显示错误信息。
 -v: 显示不被pattern 匹配到的行,相当于[^] 反向匹配
 -w :匹配 整个单词

案例

测试文件:

# lsb_release -a
LSB Version:	:core-4.1-amd64:core-4.1-noarch
Distributor ID:	AlibabaCloud
Description:	Alibaba Cloud Linux release 3 (Soaring Falcon)
Release:	3
Codename:	SoaringFalcon

1、忽略大小写匹配;

忽略大小写匹配cloud

lsb_release -a | grep -i cloud

2.查看匹配内容的行数

查看匹配内容在哪一行;

lsb_release -a | grep -i -n cloud

3. 打印匹配内容上下文内容

打印文件的前一行,后一行,上下行

lsb_release -a | grep -A 1  Release
lsb_release -a | grep -B 1  Release
lsb_release -a | grep -C 1  Release

4. 精确匹配单词

精确匹配某个单词:

lsb_release -a | grep -w Cloud

5. 正则表达式匹配内容

正则表达式匹配文件内容,并且只展示检索到的内容;

egrep -o 'client(.*)? server' /var/log/nginx/error.log

其他常用的正则规则:

? 前面的字符是可选的和只匹配一次 * 前面的字符可以匹配0此或者更多次 + 前面的字符至少匹配一次,可以匹配更多次 {n} 前面的字符精确匹配 n 此 {n,}前面的字符匹配n此以上 {,m}前面的字符至多匹配m次 ():向后引用,引用:\1, \2, \3 ^ 行首锚定,用于模式的最左侧 行尾锚定,用于模式的最右侧 `^` 空行,去除空行一般是egrep -v '^$' file

Sed - 修改目标内容

Sed(stream editor)流失编辑器,grep命令是用来做文本搜索的,那么sed命令除了搜索之外还包含:文本新增,替换,文本删除

Sed一次处理一行内容。处理时,把当前处理的行存储在临时缓冲区中,称为“模式空间”(patternspace ),接着用sed 命令处理缓冲区中的内容,处理完成后,把缓冲区的内容送往屏幕。然后读入下行,执行下一个循环。如果没有使诸如‘D’ 的特殊命令,那会在两个循环之间清空模式空间,但不会清空保留空间。这样不断重复,直到文件末尾。文件内容并没有改变,除非你使用重定向存储输出或-i。

image.png

语法

sed script [-Ealn] [-i extension] [file ...]
sed [-Ealn] [-i extension] [-e script] ... [-f script_file] ... [file ...]
-e 指定脚本,可以指定多个脚本
-f 指定读取脚本的文件
-n 静默模式,取消控制台输出,如果与-p结合使用的话,打印指定内容
-i 输出到原文件,就是修改原文件内容

script:
a 新增
d 删除
i 插入
p 打印
s 替换

案例

还是通过实际案例,学习下如何使用Sed吧;

1. 打印目标内容,行范围、匹配

查看文本中的某些行的内容,和Grep功能比较类似

#多打印第二行
lsb_release -a | sed '2 p'   

# 只打印第二行
lsb_release -a | sed -n '2 p'   

# 只打印2,4行
lsb_release -a | sed -n '2,4 p'   

# 只打印匹配到的行
lsb_release -a | sed -n '/Cloud/ p'   

# 忽略大小写打印匹配到的行
lsb_release -a | sed -n '/Cloud/I p'   

2. 在输出中新增内容

在文件中新增某些内容:i,a

# 第一行下面新增aihe
lsb_release -a | sed  '1a aihe'
# 第一行上面新增aihe
lsb_release -a | sed  '1i aihe'
# 匹配到clound之后新增aihe
lsb_release -a | sed  '/cloud/Ia aihe'

3. 删除输出中的匹配内容

删除某些不需要的行,和打印命令是一对相反操作,了解了打印,删除页也没问题。

# 删除文件的1~3行
lsb_release -a | sed  '1,3d'

# 删除文件的第一行
lsb_release -a | sed  '1d'

# 删除文件中匹配到的某些内容
lsb_release -a | sed  '/Cloud/d'

4. 替换输出中的匹配内容

直接替换掉文件中的某些内容,这个比较常用,直接使用命令替换文件内容。

# 替换掉文件行中第一次出现的cloud为aihe
lsb_release -a | sed  's/Cloud/aihe/'

# 只替换文件中第二行出现的Cloud
lsb_release -a | sed  '2s/Cloud/aihe/'

# 文件中所有出现过的Cloud都替换为aihe
lsb_release -a | sed  '2s/Cloud/aihe/g'

# 替换一行中第二次出现的字符
lsb_release -a | sed 's/Cloud/aihe/2' 

AWK - 文件内容统计

Awk是一种脚本语言,主要用于操作数据和生成报告(数据统计)。 Awk有很多内建的功能,比如数组、函数等,不过一般简单的使用方式就足以满足绝大部分诉求了。

awk.png

语法

awk -f programfile file
awk [options] 'BEGIN{ action;… } pattern{ action;… } END{ action;… }' file ...

# 常用的命令选项
-f progfile	  awk程序文件,awk从-f指定的文件中读取要执行的awk程序。
-F fs  指定awk以什么作为分隔符
-v var=val  分配变量

AWK内置了一些变量,可以在命令行中直接使用:

ARGC               命令行参数个数
ARGV               命令行参数排列
ENVIRON            支持队列中系统环境变量的使用
FILENAME           awk浏览的文件名
FNR                浏览文件的记录数
FS                 设置输入域分隔符,等价于命令行 -F选项
NF                 记录中总的列数;
NR                 已读的记录数
OFS                输出域分隔符
ORS                输出记录分隔符
RS                 控制记录分隔符
$0变量是指整条记录。$1表示当前行的第一个域,$2表示当前行的第二个域,......以此类推。

$NF是number finally,表示最后一列的信息,跟变量NF是有区别的,变量NF统计的是每行列的总数

如果有不确定的内置变量信息, 可以直接man awk,内部会对这些变量有些解释。自定义变量同上面的命令行选项: -v var1=v1

案例

1. 按分隔符分隔内容查看

读取所有java进程的pid,以及当前进程的用户,awk默认使用 空格或者\t作为分隔符。

ps -ef | grep java | grep -v grep | awk '{print $1,$2}'

从/etc/passwd中查看系统中所有的用户 -F 制定分隔符为: 然后直接执行打印动作即可。

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

2. 使用内置变量统计内容

打印监听的端口与当前端口对应的行数

  • NR,上面说到NR是AWK的内置变量;
ss -tnl | awk '{print NR,$4}'

统计当前系统的网络状态

  • $NF 使用最后一列的字段值
netstat -n | awk '/^tcp/ {++state[$NF]} END {for(key in state) print key,"\t",state[key]}'

3. 对某列统计计数与排序

统计Nginx中访问次数前10的IP地址以及个数:

cat access.log | awk '{++state[$1]} END {for(key in state) print state[key],"\t",key}' | sort -n -r | head -n 10

Nginx中有错误日志的IP地址以及错误访问次数:

awk -F'client' '{print $2}' error.log | awk  '{print $2,$7}' | awk -F',' '{++state[$1]} END {for(key in state) print state[key],"\t",key}' | sort -n -r

总结

  • 个人服务器有时候需要到服务器上捞一些日志,统计一些日志,Linux自带的命令可以帮助我们很好的做这件事,便宜并且功能强大.
  • Grep主要用于文件搜索,Sed用于文件的修改,Awk用于文件内容的统计;
  • 然后分享了下一些常用的grep、sed、awk命令案例;

最后还要提下Linux的命令在单机模式下确实非常的强大,但是在生产环境的时候,一般是集群部署,还需要辅助一些运维工具,批量执行命令。 但是如果是单机模式,掌握了这几个命令,应对绝大多数场景都没问题。

希望能对大家有所帮助。