介绍
grep awk sed是Linux下文本处理常用的命令,能完成很多神奇的操作,今天就分享一下这三个命令最常见的用法
grep
使用一般有如下两种形式
第一种形式
代码语言:javascript复制grep [option] [pattern] [file1,file2]
如查找show.txt里面包含content的行
代码语言:javascript复制grep content show.txt
第二种形式
代码语言:javascript复制command | grep [option] [pattern]
如查看某个服务信息
代码语言:javascript复制ps -ef | grep mongo
如查找show.txt里面包含content的行
代码语言:javascript复制cat show.txt | grep content
必须掌握的选项
选项 | 含义 |
---|---|
-v | 显示不匹配行信息(反向搜索) |
-i | 搜索时忽略大小写 |
-n | 显示行号(文件中的行号) |
-r | 递归搜索(搜索文件夹) |
-E | 支持扩展正则表达式 |
-F | 不按正则表达式匹配,按照字符串字面意思匹配 |
cat show.txt
a
b
c
d
py*
i love python
-v 选项
代码语言:javascript复制grep -v a show.txt
b
c
d
*py
i love python
-n选项
代码语言:javascript复制grep -n a show.txt
1:a
-r选项 查找/etc/myconfig及其子目录下,打印出包含content字符串所在行的内容
代码语言:javascript复制 grep -r content /etc/myconfig
-F选项
代码语言:javascript复制grep py* show.txt
py*
i love python
py被当成正则表达式处理,我就想搜索py这个内容,就可以用到-F选项
代码语言:javascript复制grep -F py* show.txt
py*
了解的选项
选项 | 含义 |
---|---|
-c | 只输出匹配行的数量,不显示具体内容 |
-w | 匹配整词 |
-x | 匹配整行 |
-l | 只列出匹配的文件名,不显示具体匹配行内容 |
cat show.txt
love
lovelove
i love
i love a
-w选项(lovelove这个词没有显示出来,因为love前后得有空格或者tab才会认为是一个单词)
代码语言:javascript复制grep -w love show.txt
love
i love
i love a
-x 选项(匹配行,行的内容只能是i love a)
代码语言:javascript复制grep -x "i love a" show.txt
i love a
这些选项可以混着用,例如
查找/etc/myconfig及其子目录下,打印出包含content字符串所在文件的文件名
代码语言:javascript复制grep -rl abc /etc/myconfig
-r:递归搜索(搜索文件夹) -l:只列出匹配的文件名,不显示具体匹配行内容
当然用find也是可以的,只不过麻烦一点
代码语言:javascript复制find /etc/myconfig -type f | xargs grep -l abc
这个命令在看配置的是时候还是挺管用的
查看日志常用的选项
选项 | 含义 |
---|---|
-C n | 显示匹配行及其前后5行 |
-B n | 显示匹配行及其前5行 |
-A n | 显示匹配行及其后5行 |
cat show.txt
1
2
3
4
5
6
7
查找4及其上下2行
代码语言:javascript复制cat show.txt | grep -C 2 4
2
3
4
5
6
查找4及其前2行
代码语言:javascript复制grep -B 2 4 show.txt
2
3
4
grep和egrep的区别和联系
grep默认不支持扩展正则表达式,只支持基础正则表达式 使用grep -E 可以支持扩展正则表达式 使用egrep可以支持扩展正则表达式,与grep -E等价
awk
使用一般有如下两种形式
第一种形式
代码语言:javascript复制awk 'BEGIN{}pattern{commands}END{}' file_name
语法格式 | 解释 |
---|---|
BEGIN | 正式处理数据之前 |
pattern | 匹配模式 |
{commands} | 匹配命令,可能多行 |
END | 处理完所有匹配数据后执行 |
第二种形式
代码语言:javascript复制standard output | awk 'BEGIN{}pattern{commands}END{}'
awk的内置变量
内置变量 | 含义 |
---|---|
$0 | 整行内容 |
n | 当前行的第1-n个字段(按照指定分隔符分割后) |
NF(Number Field) | 当前行的字段个数,也就是多少列 |
NR(Number Row) | 当前行的行号,从1开始计数 |
FNR(File Number Row) | 多文件处理时,每个文件行号单独计数,都是从0开始 |
FS(Field Separator) | 输入字段分割符。不指定默认以空格或者Tab键分割 |
RS(Row Separator) | 输入行分割符。默认回车n |
OFS(Output Field Sepatator) | 输出字段分割符。默认为空格 |
ORS(Output Row) | 输出行分隔符。默认为回车 |
FILENAME | 当前输入的文件名字 |
ARGC | 命令行参数个数 |
ARGV | 命令行参数数组 |
看一下/etc/passwd文件的内容
代码语言:javascript复制cat /etc/passwd
root:x:0:0:root:/root:/bin/bash
bin:x:1:1:bin:/bin:/sbin/nologin
daemon:x:2:2:daemon:/sbin:/sbin/nologin
输出文件的每行内容
代码语言:javascript复制# $0为整行内容
awk '{print $0}' /etc/passwd
root:x:0:0:root:/root:/bin/bash
bin:x:1:1:bin:/bin:/sbin/nologin
daemon:x:2:2:daemon:/sbin:/sbin/nologin
输出第二列内容
需要指定分隔符:
代码语言:javascript复制# $2为第二列内容
awk 'BEGIN{FS=":"}{print $2}' /etc/passwd
x
x
x
不需要指定分割符,默认空格,tab键,多个也可以分隔(如一个空格 一个tab键)
代码语言:javascript复制cat show.txt
# 空格分隔
python java php
# tab键分隔
flink hadoop storm
输出第一列内容
代码语言:javascript复制awk '{print $1}' show.txt
python
flink
输出每一行有多少列
代码语言:javascript复制awk '{print NF}' show.txt
3
3
可以用这个输出每一行的最后一列的值
代码语言:javascript复制awk '{print $NF}' show.txt
输出行号
代码语言:javascript复制awk '{print NR}' show.txt
1
2
对每个文件的行号单独计数(显示show.txt和/etc/passwd文件的行号,不累加)
代码语言:javascript复制awk '{print FNR}' show.txt /etc/passwd
1
2
1
2
...
同时指定行分隔符和列分隔符
代码语言:javascript复制cat show.txt
python|java|php--flink|hadoop|storm
先输出每一行数据
代码语言:javascript复制# RS为指定行分隔符
awk 'BEGIN{RS="--"}{print $0}' show.txt
python|java|php
flink|hadoop|storm
输出每一行的第二列
代码语言:javascript复制# RS指定行分隔符
# FS指定列分隔符
awk 'BEGIN{RS="--";FS="|"}{print $2}' show.txt
java
hadoop
在上面基础上指定行分隔符
代码语言:javascript复制# ORS 输出行分割符
awk 'BEGIN{RS="--";FS="|";ORS="&"}{print $2}' show.txt
java&hadoop&
再次指定列分隔符
代码语言:javascript复制# OFS输出列分隔符
awk 'BEGIN{RS="--";FS="|";ORS="&";OFS="@@"}{print $1,$2}' show.txt
python@@java&flink@@hadoop&
输出文件名字
代码语言:javascript复制cat show.txt
python|java|php
flink|hadoop|storm
代码语言:javascript复制awk '{print FILENAME}' show.txt
show.txt
show.txt
因为是对行进行处理,所以有几行,输出几次文件名
当然awk还有其他强大的操作,如支持函数,流程控制,格式化输出等。有兴趣的可以了解一下awk编程,这里就不再多做介绍了
假如有一个如下的访问日志request.log
代码语言:javascript复制2020-05-21 request enter
2020-05-21 request ip 127.0.0.1
2020-05-21 request finish
2020-05-21 request enter
2020-05-21 request error
2020-05-21 request enter
2020-05-21 request ip 127.0.0.1
2020-05-21 request finish
2020-05-21 request enter
2020-05-21 request ip 11.25.58.21
2020-05-21 request finish
想统计当日去重后的ip有多少个,就可执行如下命令
代码语言:javascript复制# sort为排序,uniq为去重
cat request.log | grep ip | awk '{print $4}' | sort | uniq
11.25.58.21
127.0.0.1
我原来维护了一个hadoop集群,当想关闭集群中的所有DataNode节点(可以认为一个应用),假如每个机器jps,查看pid,kill。很麻烦,直接写了一个脚本,依次ssh到各个节点,然后执行如下命令即可,超级省事
代码语言:javascript复制kill `jps | grep 'DataNode' | awk '{print $1}'`
sed
sed的功能和文本编辑器有点类似,因为我在Linux对文本进行修改用vim比较多,sed的话可能在脚本中用的多一点,因此也没多少经验,简单介绍一个替换的示例
代码语言:javascript复制cat show.txt
this is a test for sed
this is second line
# 将second替换为first输出到屏幕,文件内容并没有改变
# 有选项可以指定,不再介绍
sed 's/second/first/' show.txt
this is a test for sed
this is first line