Linux:grep+awk+sed

1. grep:基于正则表达式查找满足条件的行
1.1 内容检索

注:pattern代表正则表达式,所以需要懂正则表达式

  • 获取行:grep pattern file
  • 获取内容:grep -o pattern file
  • 获取上下文:grep -A -B -C pattern file -A和-B后面需要一个数字
[jck253509@shell.ceshiren.com shell]$ cat grep_test
a, 1, 20
a, 2, 20
a, 3, 20
b, 1, 1
b, 2, 2
b, 3, 3
c, 1, 21
c, 2, 30
c, 3, 89
[jck253509@shell.ceshiren.com shell]$ grep a grep_test
a, 1, 20
a, 2, 20
a, 3, 20
[jck253509@shell.ceshiren.com shell]$ grep 1 grep_test
a, 1, 20
b, 1, 1
c, 1, 21
[jck253509@shell.ceshiren.com shell]$ grep ", 1, " grep_test
a, 1, 20
b, 1, 1
c, 1, 21
[jck253509@shell.ceshiren.com shell]$ grep "1$" grep_test
b, 1, 1
c, 1, 21
[jck253509@shell.ceshiren.com shell]$ grep -o "1$" grep_test
1
1
[jck253509@shell.ceshiren.com shell]$ grep -o "[0-9]*1$" grep_test
1
21
[jck253509@shell.ceshiren.com shell]$ grep -A2 -B2 "2," grep_test
a, 1, 20
a, 2, 20
a, 3, 20
b, 1, 1
b, 2, 2
b, 3, 3
c, 1, 21
c, 2, 30
c, 3, 89
[jck253509@shell.ceshiren.com shell]$ grep -A1 -B1 "2," grep_test
a, 1, 20
a, 2, 20
a, 3, 20
b, 1, 1
b, 2, 2
b, 3, 3
c, 1, 21
c, 2, 30
c, 3, 89
[jck253509@shell.ceshiren.com shell]$ grep -B1 "2," grep_test
a, 1, 20
a, 2, 20
--
b, 1, 1
b, 2, 2
--
c, 1, 21
c, 2, 30
1.2 文件检索:检索哪个文件里有那些内容
  • 递归搜索:grep pattern -r dir/
  • 展示匹配文件名:grep -H 111 /tmp/1
  • 只展示匹配文件名:grep -1 111 /tmp/1
1.3 范围约束
  • 忽略大小写:grep -i pattern file
  • 不显示匹配的行(不匹配的行输出):grep -v pattern file
  • 使用扩展正则表达式:grep -E pattern file
  • 文件范围和目录范围约束:grep 111 -r /tmp/demo/ --include “11*”

1.4 进程检索
  • 进程检索场景比较特殊,需要注意
  • grep本身会开启新进程,所以需要单独过滤掉grep进程
[jck253509@shell.ceshiren.com ~]$ ps -ef | grep ssh
root      4281 15082  0 12:22 ?        00:00:00 sshd: jck253509 [priv]
jck2535+  4305  4281  0 12:23 ?        00:00:00 sshd: jck253509@pts/8
root      6973 15082  0 12:51 ?        00:00:00 sshd: jck253509 [priv]
jck2535+  6978  6973  0 12:51 ?        00:00:00 sshd: jck253509@pts/9
jck2535+  7558  6979  0 12:59 pts/9    00:00:00 grep --color=auto ssh
root     10330 15082  0  2021 ?        00:00:00 sshd: quanjinlong [priv]
quanjin+ 10332 10330  0  2021 ?        00:00:00 [sshd] <defunct>
root     15082     1  0  2021 ?        00:02:35 /usr/sbin/sshd -D
root     25602 15082  0 10:28 ?        00:00:00 sshd: lg48968116 [priv]
lg48968+ 25606 25602  0 10:28 ?        00:00:00 sshd: lg48968116@pts/0
root     26462 15082  0 08:40 ?        00:00:00 sshd: ck245138 [priv]
ck245138 26527 26462  0 08:40 ?        00:00:00 sshd: ck245138@pts/7
root     29546 15082  0 11:02 ?        00:00:00 sshd: 61993657 [priv]
61993657 29561 29546  0 11:02 ?        00:00:00 sshd: 61993657@pts/4
[jck253509@shell.ceshiren.com ~]$ ps -ef | grep ssh | grep -v grep
root      4281 15082  0 12:22 ?        00:00:00 sshd: jck253509 [priv]
jck2535+  4305  4281  0 12:23 ?        00:00:00 sshd: jck253509@pts/8
root      6973 15082  0 12:51 ?        00:00:00 sshd: jck253509 [priv]
jck2535+  6978  6973  0 12:51 ?        00:00:00 sshd: jck253509@pts/9
root     10330 15082  0  2021 ?        00:00:00 sshd: quanjinlong [priv]
quanjin+ 10332 10330  0  2021 ?        00:00:00 [sshd] <defunct>
root     15082     1  0  2021 ?        00:02:35 /usr/sbin/sshd -D
root     20325 15082  0 Oct23 ?        00:00:00 sshd: yangchenhui [priv]
yangche+ 20328 20325  0 Oct23 ?        00:00:00 sshd: yangchenhui@pts/12
root     25602 15082  0 10:28 ?        00:00:00 sshd: lg48968116 [priv]
lg48968+ 25606 25602  0 10:28 ?        00:00:00 sshd: lg48968116@pts/0
root     26462 15082  0 08:40 ?        00:00:00 sshd: ck245138 [priv]
ck245138 26527 26462  0 08:40 ?        00:00:00 sshd: ck245138@pts/7
root     29546 15082  0 11:02 ?        00:00:00 sshd: 61993657 [priv]
61993657 29561 29546  0 11:02 ?        00:00:00 sshd: 61993657@pts/4
1.5 man grep …

参考:Linux基本命令

2. awk:根据定位到的数据行处理其中的分段
2.1 awk的基本语法
  • awk是linux下的一个命令,同时也是一种语言解析引擎
  • awk具备完整的编程特性。比如执行命令,网络请求等
  • 精通awk,是一个linux工作者的必备技能
  • 语法awk ’pattern{action}‘
2.2 awk上下文变量
  • 开始BEGIN结束END
  • 行数NR
  • 字段与字段数$1$2$3… $NF NF
  • 整行 $0
  • 字段分隔符 FS
  • 输出数据的字段分隔符 OFS
  • 记录分割符 RS
  • 输出字段的行分隔符ORS
2.3 字段变量用法
  • -F参数指定字段分隔符,可以用|指定多个-多分隔符-F’<|>’
  • BEGIN{FS=“_”}也可以表示分隔符
  • $0代表当前的记录,即整行
  • $1代表第一个字段
  • $N代表第N个字段
  • $NF代表最后一个字段
  • $(NF-1)代表倒数第二个字段
2.5 pattern表达式
  • 正则匹配 $1~/pattern/ /pattern/
  • 比较表达式 $2>2 $1==“b”
2.6 awk pattern 匹配表达式案例
  • 开始和结束 awk ‘BEGIN{}END{}’
  • 正则匹配
    • 整行匹配 awk ‘/Running/’
    • 字段匹配 awk ‘$2~/xxx/’
  • 行数表达式
    • 取第二行 awk ‘NR==2’
    • 去掉第一行 awk ‘NR>1’
  • 区间选择
    • awk ‘/aa/, /bb/’
    • awk ‘/1/, NR==2’
2.7 action表达式{action}
  • 打印:{print $0} {print $2}
  • 赋值 {$1=“abc”}
  • 处理函数
  • 原始内容$0
  • 更新后内容{$1=$1;print $0}
2.8 计算平均数
  • 看下面bash
2.9 awk的词典结构array
  • array是稀疏矩阵,类似python的词典类型
  • 统计多家机构的营业额:看下面的bash
  • 统计多家机构的营业额平均值:看下面的bash
[jck253509@shell.ceshiren.com shell]$ echo '1
> 2
> 3
> 4' | awk 'NR==2'
2
[jck253509@shell.ceshiren.com shell]$ echo '1
2
3
4' | awk '$1~/3/'
3
[jck253509@shell.ceshiren.com shell]$ echo '1
2
3
4' | awk '/3/'
3
[jck253509@shell.ceshiren.com shell]$ echo '1
2
3
4' | awk '/3/{print $0}'
3
[jck253509@shell.ceshiren.com shell]$ echo '1
2
3
4' | awk 'NR>2'
3
4
[jck253509@shell.ceshiren.com shell]$ echo '1
2
3
4' | awk '/1/,/2/'
1
2
[jck253509@shell.ceshiren.com shell]$ echo '1
2
3
4' | awk '/1/,/3/'
1
2
3
[jck253509@shell.ceshiren.com shell]$ echo 1:2:3 | awk 'BEGIN{RS=":"}{print $0}'
1
2
3
[jck253509@shell.ceshiren.com shell]$ echo '1
2
3' | awk 'BEGIN{RS="";FS="\n";OFS=":"}{$1=$1;print $0}'
1:2:3
[jck253509@shell.ceshiren.com shell]$ echo '1
2
3' | awk 'BEGIN{ORS=":"}{$1=$1;print $0}'
1:2:3:
[jck253509@shell.ceshiren.com shell]$ echo '1,20
> 2,20
> 3,30' | awk 'BEGIN{total=0;FS=","}{total+=$2}END{print total/NR}'
23.3333
[jck253509@shell.ceshiren.com shell]$ echo 'a, 1, 10
a, 2, 20
> a, 3, 30
> b, 1, 5
> b, 2, 6
> b, 3, 7' | awk '{data[$1]+=$3}END{for(k in data) print k, data[k]}'
a, 60
b, 18
[jck253509@shell.ceshiren.com shell]$ echo 'a, 1, 10
a, 2, 20
a, 3, 30
b, 1, 5
b, 2, 6
b, 3, 7' | awk '{data[$1]+=$3;count[$1]+=1;}END{for(k in data) print k, data[k]/count[k]}'
a, 20
b, 6
3. sed:stream editor 定位并修改数据
3.1 sed基本语法与常用参数
  • 语法结构 sed [addr]X[options]
  • -e表达式
  • sed -n ‘2p’ 打印第二行
  • sed ‘s#hello#world#’ 修改
  • -i 直接修改源文件
  • -E扩展表达式
  • -debug调试
3.2 sed pattern表达式
  • 行数与行数范围 20,30,35
  • 正则匹配 /pattern/
  • 区间匹配 //,//
3.3 sed action表达式
  • p打印,通畅结合-n参数:sed -n ‘2p’
  • s查找替换:s/REGEXP/REPLACEMENT/[FLAGS]
  • d删除,删除前两行 sed ‘1, 2d’
  • a追加
  • c改变
  • i插入内容到匹配行之前
# -i在匹配行前加上123
[jck253509@shell.ceshiren.com shell]$ echo abd | sed '/d/i 123'
123
abd
# -a在匹配行后加上123
[jck253509@shell.ceshiren.com shell]$ echo abd | sed '/d/a 123'
abd
123
# -c将匹配的内容行修改为123
[jck253509@shell.ceshiren.com shell]$ echo abd | sed '/d/c 123'
123
  • e执行命令
  • 分组匹配到字段提取:sed ‘s#([0-9])|([a-z])#\1\2#’
[jck253509@shell.ceshiren.com shell]$ cat grep_test
a, 1, 20
a, 2, 20
a, 3, 20
b, 1, 1
b, 2, 2
b, 3, 3
c, 1, 21
c, 2, 30
c, 3, 89
# 打印第二行
[jck253509@shell.ceshiren.com shell]$ sed -n '2p' grep_test
a, 2, 20
# 打印2-4行
[jck253509@shell.ceshiren.com shell]$ sed -n '2,4p' grep_test
a, 2, 20
a, 3, 20
b, 1, 1
# 打印匹配到的b
[jck253509@shell.ceshiren.com shell]$ sed -n '/b/p' grep_test
b, 1, 1
b, 2, 2
b, 3, 3
3.4 行数操作
  • 打印特定行:sed -n 2p
  • 删除最后一行:sed $d
3.5 s表达式
  • s表示替换:echo a:b:c| sed ‘s/:/123&/’
  • s后面表示的追加字符可以为任意字符:echo a:b:c | sed 's/:/&123/'
  • g表示全局匹配:echo a:b:c | sed 's#:#|#g'
  • &表示匹配内容
# 删除最后一行 $表示最后一行
[jck253509@shell.ceshiren.com shell]$ sed '$d' grep_test
a, 1, 20
a, 2, 20
a, 3, 20
b, 1, 1
b, 2, 2
b, 3, 3
c, 1, 21
c, 2, 30
# 删除前三行
[jck253509@shell.ceshiren.com shell]$ sed '1,3d' grep_test
b, 1, 1
b, 2, 2
b, 3, 3
c, 1, 21
c, 2, 30
c, 3, 89
# 在第一个匹配内容的前面加123
[jck253509@shell.ceshiren.com shell]$ echo a:b:c | sed 's/:/123&/'
a123:b:c
# 在第一个匹配内容的后面加123
[jck253509@shell.ceshiren.com shell]$ echo a:b:c | sed 's/:/&123/'
a:123b:c
# 将所有的:修改为| g表示全局修改
[jck253509@shell.ceshiren.com shell]$ echo a:b:c | sed 's#:#|#g'
a|b|c
# 将a修改为great_a
[jck253509@shell.ceshiren.com shell]$ sed 's/a/great_a/' grep_test
great_a, 1, 20
great_a, 2, 20
great_a, 3, 20
b, 1, 1
b, 2, 2
b, 3, 3
c, 1, 21
c, 2, 30
c, 3, 89
# 将a修改为great_a,可以使用/表示 也可以使用#表示
[jck253509@shell.ceshiren.com shell]$ sed 's#a#great_a#' grep_test
great_a, 1, 20
great_a, 2, 20
great_a, 3, 20
b, 1, 1
b, 2, 2
b, 3, 3
c, 1, 21
c, 2, 30
c, 3, 89
# 将所有以1结尾的数修改为100
[jck253509@shell.ceshiren.com shell]$ sed 's#1$#100#' grep_test
a, 1, 20
a, 2, 20
a, 3, 20
b, 1, 100
b, 2, 2
b, 3, 3
c, 1, 2100
c, 2, 30
c, 3, 89
# 将每行第一个匹配到的内容修改为100
[jck253509@shell.ceshiren.com shell]$ sed 's#1#100#' grep_test
a, 100, 20
a, 2, 20
a, 3, 20
b, 100, 1
b, 2, 2
b, 3, 3
c, 100, 21
c, 2, 30
c, 3, 89
# 将每行第一个匹配到的内容修改为9
[jck253509@shell.ceshiren.com shell]$ sed 's#1#9#' grep_test
a, 9, 20
a, 2, 20
a, 3, 20
b, 9, 1
b, 2, 2
b, 3, 3
c, 9, 21
c, 2, 30
c, 3, 89
# 将所有的1修改为9
[jck253509@shell.ceshiren.com shell]$ sed 's#1#9#g' grep_test
a, 9, 20
a, 2, 20
a, 3, 20
b, 9, 9
b, 2, 2
b, 3, 3
c, 9, 29
c, 2, 30
c, 3, 89
# 将所有匹配到的内容前加123
[jck253509@shell.ceshiren.com shell]$ echo a:b:c | sed 's/:/123&/g'
a123:b123:c
# 将所有匹配到的内容前加12,后加3
[jck253509@shell.ceshiren.com shell]$ echo a:b:c | sed 's/:/12&3/g'
a12:3b12:3c
3.6 反向引用
  • 使用()对数据进行分组
  • 使用\1\2反向引用分组
# ([1-3])定位到一个1-3的数字,-E表示扩展正则
[jck253509@shell.ceshiren.com shell]$ echo 0 1 2 3 4 | sed -E 's#([1-3]) ([1-3]) ([1-3])#\3 \2 \1#'
0 3 2 1 4
4. 匹配管道使用:shell管道piping
4.1 程序运行环境输入与输出
  • 标准输入0:read a; echo $a
  • 标准输出1:echo ceshiren.com
  • 错误输出2:ls not_exist_dir
[jck253509@shell.ceshiren.com shell]$ read a;
9090
[jck253509@shell.ceshiren.com shell]$ echo $a
9090
[jck253509@shell.ceshiren.com shell]$ ls not_exist_dir
ls: cannot access not_exist_dir: No such file or directory
4.2 管道重定向
  • 管道与管道之前可以重定向
  • 管道与文件之前可以重定向
# 从文件中读取一行,存储到变量a中
[jck253509@shell.ceshiren.com shell]$ read a < grep_test
# 打印变量a
[jck253509@shell.ceshiren.com shell]$ echo $a
a, 1, 20
# 将内容输入到文件中,文件内容被修改
[jck253509@shell.ceshiren.com shell]$ echo 111 > grep_test
[jck253509@shell.ceshiren.com shell]$ cat grep_test
111
# 将错误信息输出到文件中 2>&1将标准错误输出重定向到标准错误输出中
[jck253509@shell.ceshiren.com shell]$ ls not_exist_file > grep_test 2>&1
[jck253509@shell.ceshiren.com shell]$ cat grep_test
ls: cannot access not_exist_file: No such file or directory
4.3 管道连接符 |
  • 管道连接符 | 可以连接多个程序的执行
  • 管道连接是以子进程的方式启动的
# 输入和输出使用管道连接
[jck253509@shell.ceshiren.com shell]$ echo hogwarts | { read line; echo input is $line;}
input is hogwarts
# curl访问一个网站, {"id[^}]*}表示匹配从"id往右的第一个}
[jck253509@shell.ceshiren.com shell]$ curl https://ceshiren.com/categories.json \
| grep -o '{"id[^}]*}' \
| awk -F, '{print $2, $6}' \
| awk -F '"' '{print $7, $4}' \
| sed 's#:##' \
| sort -nr \
| head -5
  % Total    % Received % Xferd  Average Speed   Time    Time     Time  Current
                                 Dload  Upload   Total   Spent    Left  Speed
100 13227    0 13227    0     0  44709      0 --:--:-- --:--:-- --:--:-- 44837
1622 霍格沃兹答疑区
619 职位内推
535 开源项目
301 测试开发
201 霍格沃兹测试开发学社
4.4 管道执行的上下文控制
  • 使用{command;}注意花括号与内部命令之间的空格与分号
  • 使用控制逻辑while read组合
  • 使用$()" echo $a
# 这个方式无法获得变量x
echo hello world | read x; echo $x
# 如下两个方式可以获得变量x
echo hello world | { read x; echo $x;}
echo hello world | while read x; do echo $x; done
4.5 平台实现差异与官方文档
  • mac上的实现与gnu的实现有差异
  • 不同版本之前有小的语法差异
  • 可以通过独立下载gawk等工具实现
  • 官方文档
    • https://www.gnu.org/software/grep/manual/grep.html
    • https://www.gnu.org/software/gawk/manual/gawk.html
    • https://www.gnu.org/software/sed/manual/sed.html
4.6 BRE基本正则表达式
  • ^开头$结尾
  • [a-z][0-9]区间,如果开头带有^表示不能匹配区间内的元素
  • *0个或多个
  • . 表示任意字符
4.7 BRE扩展正则表达式
  • 基本正则表达式(BRE)基础上的扩展
  • ?非贪婪匹配,匹配前面的子表达式零次或一次
  • +一个或者多个
  • ()分组
  • {}范围约束
  • | 匹配多个表达式的任何一个
echo 123 | grep -E "1|3"
sed -E -e "s#1|3#x#g"
echo 123 | awk '/4|3/'
5. Nginx日志分析实战
5.1 找出log中的404和500的报错
# 使用grep实现
less nginx.log | grep -E '(" 404 |" 500 )'
# 使用awk实现
less nginx.log | awk '$9~/404|500/{print $0}' 或者
less nginx.log | awk '$9~/404|500/' 或者
less nginx.log | awk '$9==404 || $9==500/'
5.2 找出访问量最高的ip,统计分析,取出top3的ip和数量
less nginx | awk 'print $1' | sort | uniq -c | sort -nr | head -3
或者
awk '{print $1}' nginx.log | sort | uniq -c | sort -nr | awk 'NR<4'
6 性能及网站统计
6.1 统计一个进程的实时cpu数据需要用到哪个命令
# 关注进程
# STIME开始运行时间 TTY是否有交互 TIME运行时长  CMD最后执行的命令
[jck253509@shell.ceshiren.com ~]$ ps -ef | head -3
UID        PID  PPID  C STIME TTY          TIME CMD
root         1     0  0  2020 ?        10:01:02 /usr/lib/systemd/systemd --system --deserialize 21
root         2     0  0  2020 ?        00:00:08 [kthreadd]
# 关注性能
[jck253509@shell.ceshiren.com ~]$ ps aux | head -5
USER       PID %CPU %MEM    VSZ   RSS TTY      STAT START   TIME COMMAND
root         1  0.0  0.0 191120  3148 ?        Ss    2020 601:02 /usr/lib/systemd/systemd --system --deserialize 21
root         2  0.0  0.0      0     0 ?        S     2020   0:08 [kthreadd]
root         3  0.0  0.0      0     0 ?        S     2020   7:56 [ksoftirqd/0]
root         5  0.0  0.0      0     0 ?        S<    2020   0:00 [kworker/0:0H]
# 自定义ps
ps_ex(){ ps -o uname,pid,ppid,thcount,ni,pri,psr,pcpu,rss,vsz,sz,start_time,time,comm,c,command,args,"$@";}
}

ps打印的是cpu快照,不是实时的cpu,不可以看性能指标;
top打印的是实时的,可以看性能指标

6.2 统计一个进程的性能:根据pid打印cpu和mem
# 输出20s内某个进程的每秒的cpu和mem,并最后空出一行统计平均性能
top -p 22985 -b -d 1 -n 20 | grep --line-buffered -i aliyun | grep -i dun
top -b -d 1 -n 20 | grep --line-buffered -i yundun$ | awk 'BEGIN{print "cpu", "mem"}{cpu+=$9;mem+=$10; print $9,$10}END{print "";print cpu/NR, mem/NR}'
6.3 网络命令
  • netstat -tlnp
  • netstat -tnp
  • mac与linux不一致:netstat -p tcp -n -a
# 统计链接22端口的ip分布情况
 netstat -tn | awk 'NR>2{ print $4,$6 }' | awk -F: '{ print $2 }' | sort | uniq -c | sort -nr | awk '{ print $2"\t"$3"\t"$1}'
 
[jck253509@shell.ceshiren.com shell]$ connect(){ netstat -tn | awk 'NR>2{ print $4,$6 }' | awk -F: '{ print $2 }' | soiq -c | sort -nr | awk '{ print $2"\t"$3"\t"$1}'; }
[jck253509@shell.ceshiren.com shell]$ type connect
connect is a function
connect ()
{
    netstat -tn | awk 'NR>2{ print $4,$6 }' | awk -F: '{ print $2 }' | sort | uniq -c | sort -nr | awk '{ print $2"\t"$3"\t"$1}'
}
注意点:

1、grep和正则玩

[root@moli tmp]# grep -nvE r+ b.txt   // grep和扩展正则玩的时候  需要加上-E
4:dchjdewi

2、双引号和单引号的区别

  • 双引号会对字符串转义       # a=10 echo “$a” 打印10

3、练习 awk + grep + sed

# 1、日志操作:找出log中404 500的报错条数
grep -E "\s404\s | \s500\s" nginx.log | wc -l
awk  '$9~/404|500/' nginx.log | wc -l

# 2、awk  支持扩展正则  不需要 +E

# 3、访问量最高的ip
awk '{print $1}' nginx.log | sort | uniq -c | sort -nr | head -3
cat access.log/ | grep -o '^[0-9]*.[0-9]*.[0-9]*.[0-9]*' | sort | uniq -c | sort -rn | head -3

# 4、将topics后面的数字替换成number
grep '/topics/' nginx.log | sed 's@/topics/[0-9]*@/topics/number@'

# 5、将ip地址横向打印
awk '{print $1}' nginx.log | sed ':1;N;s/\n/|/;t1'
# :1和t1是一个组合,代表打一个标记,t1就是跳转到标记处(对命令打标记)

# 6、sed 中的  /  可以使用  # 或 @ 替换
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值