linux--三剑客 grep sed awk 用法

正则表达式
\       转义符,将特殊字符进行转义,忽略其特殊意义 
^       匹配行首,awk中,^则是匹配字符串的开始  
$       匹配行尾,awk中,$则是匹配字符串的结尾
^$      表示空行 
.       匹配除换行符\n之外的任意单个字符 
.*      匹配所有
[ ]     匹配包含在[字符]之中的任意一个字符 
[^ ]    匹配[^字符]之外的任意一个字符 
[ - ]   匹配[]中指定范围内的任意一个字符 
?       匹配之前的项1次或者0次 
+       匹配之前的项1次或者多次 
*       匹配之前的项0次或者多次, .* 
()      匹配表达式,创建一个用于匹配的子串 
{ n }   匹配之前的项n次,n是可以为0的正整数 
{n,}    之前的项至少需要匹配n次 
{n,m}   指定之前的项至少匹配n次,最多匹配m次,n<=m 
|       交替匹配|两边的任意一项ab(c|d)匹配abc或abd 
\cx	匹配由x指明的控制字符。例如, \cM 匹配一个 Control-M 或回车符。x 的值必须为 A-Z 或 a-z 之一。否则,将 c 视为一个原义的 'c' 字符。
\f	匹配一个换页符。等价于 \x0c 和 \cL。
\n	匹配一个换行符。等价于 \x0a 和 \cJ。
\r	匹配一个回车符。等价于 \x0d 和 \cM。
\s	匹配任何空白字符,包括空格、制表符、换页符等等。等价于 [ \f\n\r\t\v]。注意 Unicode 正则表达式会匹配全角空格符。
\S	匹配任何非空白字符。等价于 [^ \f\n\r\t\v]。
\t	匹配一个制表符。等价于 \x09 和 \cI。
\v	匹配一个垂直制表符。等价于 \x0b 和 \cK。
特定字符
>[[:space:]]    空格
 
[[:digit:]]     [0-9]
 
[[:lower:]]     [a-z]
 
[[:upper:]]     [A-Z]
 
[[:alpha:]]     [a-Z]
 

grep 简单用法

grep -n -A 2 "Failed" /var/log/secure 打印出符合内容的下两行和行号
 
grep -n -B 2 "Failed" /var/log/secure 打印出符合内容的上两行和行号
 
grep -n -C 2 "Failed" /var/log/secure 打印出符合内容的上下两行和行号
 
grep -ni "[a-z]" /etc/passwd           统计所有带字母的行和行号
 
grep -n ^$ file.txt                   打印空行的行号 
 
grep -n . file.txt                    打印有内容的行和行号
 
grep -n ^$ aa.txt                     打印空行的行和行号
 
grep -v root /etc/passwd              打印不带root的行
 
grep -E "a|b" /etc/passwd             打印带有a或者b的行
 
grep -i root /etc/passwd              打印root,不区分大小写
 
grep -R root /etc                     递归查找etc下有root的行
 
grep -c . /etc/passwd                 统计行号
 
grep "[0-9]" li.txt           匹配数字所在的行"[0-9]"

grep -o "8*" l.txt            精确匹配到8

grep -E "8{1,}" l.txt       至少1次或1次以上8

sed文本处理

sed是一个流编辑器, 非交互式的编辑器,它一次处理一行内容.
处理时,把当前处理的行存储在临时缓冲区中,称为“模式空间”(pattern space)
接着用 sed 命令处理缓冲区中的内容,处理完成后, 把缓冲区的内容送往屏幕。
接着处理下一行,这样不断重复,直到文件末尾。
文件内容并没有改变,除非你 使用重定向存储输出。
Sed 要用来自动编辑一个或多个文件;简化对文件的反复操作;编写转换程序等

sed 命令格式
sed [options] 'command' file(s)
sed主要选项参数

-e 允许多项编辑
 
-n 取消默认的输出
 
-i 直接修改对应文件
 
-r 支持扩展元字符

sed内置命令参数

a  在当前行后添加一行或多行
 
i   在当前行之前插入文本
 
n   读入下一输入行,从下一条命令进行处理
 
c   在当前行进行替换修改
 
d   在当前行进行删除操作
 
p   打印匹配的行或指定行
 
!   对所选行以外的所有行应用命令
 
h   把模式空间里的内容重定向到暂存缓冲区
 
H   把模式空间里的内容追加到暂存缓冲区
 
g   取出暂存缓冲区的内容,将其复制到模式空间,覆盖该处原有内容
 
G   取出暂存缓冲区的内容,将其复制到模式空间,追加在原有内容后面
 

简单用法

sed -n ‘nd’ 删除农行 
sed -n ‘/string/d’  删除匹配内容
sed -n ‘/string/!d’  删除不是匹配的内容
sed -n ‘2s###gp’  第2行的替换
sed -n '1,5p'   打印1到5行
sed -n '/aaa/,/bbb/p' 打印aaa到bbb的行,使用与d删除
sed -n '/aaa/,10p' 打印aaa到10行
sed -r ‘s#()#\1#gp’ 后项引用,适用于组合命令|bash
sed -r 's#(Roo)#\1-alice#g' passwd  后向引用
ifconfig eth0|sed -n '2p'|sed -r 's#(^.et) (.) (net.*$)#\2#g'  后向引用
sed ‘s#n#x#’ 取消了贪婪,替换每一行的第一个
sed s#^#.*\n##g   \n换行符,可以直接开头#的行,删除行
sed  -n = 123  显示行号
sed  -n '/./ =' 123 显示有内容的行号
sed  -n '/^$/=' 123 显示空行的行号
sed -i '/^$/d' file 删除空喊 
sed -i '/aaa/c bbb' 将匹配ccc的行替换成bbb
sed -i '/aaa/!d' 删除不是aaa的行
sed '1,4i hahaha' yum.log 在第一和第4行每行之前插入哈哈哈,a是之后
sed -e '1,5d' -e '=' -e 's/reboot/shutdown/g'  删除1到5行,然后替换
sed -n '$p' file 打印文件最后一行
sed "s/^/$RANDOM.rmvb_/g" #sed命令使用双引号的情况下,使用$var直接引用
sed -n '/[^dinghua]/p' 1.txt 取不是dinghua的行
sed -i.bak 's#2#3#g' 1.txt 改变的同时,将源文件拷贝成bak文件,防止修改错误
sed -r '3!d' /etc/hosts   除了第三行,其他全部删除
sed -r '/^[ \t]#/d' file   删除配置文件中含有tab键的注释行
sed '/^#/d' file 删除配置文件中#号开头的注释行, 如果碰到tab或空格是无法删除
sed -r '/^[ \t]$/d' file  删除无内容空行
 sed -r '/^[ \t]#/d; /^[ \t]$/d' vsftpd.conf 删除注释行及空行
sed -r '/^[ \t]#|^[ \t]$/d' /etc/vsftpd/vsftpd.conf 删除注释行及空行
sed -r '/^[ \t]*($|#)/d' /etc/vsftpd/vsftpd.conf  删除注释行及空行
sed '2,6s/^/#/' passwd   将第二行到第六行加上注释信息
sed -r '2,6s/.*/#&/' passwd  将第二行到第六行最前面添加#注释符

w:写文件命令

sed -n '/root/w newfile' passwd    将newfile中包含root的行写入passwd
sed -n '2w newfile' passwd    将newfile中的第二行包含root的行写入passwd

n:获取一下行命令

匹配root的行, 删除root行的下一列
[root@Shell ~]# sed '/root/{n;d}' passwd
替换匹配root行的下一列
[root@Shell ~]# sed '/root/{n; s/bin/test/}' passwd

以上为sed的常规用法,需要掌握

sed的高级用法

暂存和取用命令h H g G
将第一行的内容写入到暂存区, 替换最后一行的内容
[root@Shell ~]# sed '1h;$g' /etc/hosts

将第一行的写入到暂存区, 在最后一行调用暂存区的内容
[root@Shell ~]# sed '1h;$G' /etc/hosts

将第一行的内容删除但保留至暂存区, 在最后一行调用暂存区内容追加至于尾部
[root@Shell ~]# sed -r '1{h;d};$G' /etc/hosts

将第一行的内容写入至暂存区, 从第二行开始进行重定向替换
[root@Shell ~]# sed -r '1h;2,$g' /etc/hosts

将第一行的内容写入至暂存区, 从第二行开始进行重定向替换
[root@Shell ~]# sed -r '1h;2,$g' /etc/hosts

将第一行重定向至暂存区, 2-3行追加至暂存区, 最后追加调用暂存区的内容
[root@Shell ~]# sed -r '1h; 2,3H; $G' /etc/hosts

AWK

awk是一种编程语言,用于在linux/unix下对文本和数据进行处理。
awk数据可以来自标准输入、一个或多个文件,或其它命令的输出。
awk通常是配合脚本进行使用, 是一个强大的文本处理工具。

awk 的处理数据的方式

1.进行逐行扫描文件, 从第一行到最后一行
2.寻找匹配的特定模式的行,在行上进行操作
3.如果没有指定处理动作,则把匹配的行显示到标准输出
4.如果没有指定模式,则所有被操作的行都被处理

Awk工作原理

awk -F: '{print $1,$3}' /etc/passwd
1.awk将文件中的每一行作为输入, 并将每一行赋给内部变量$0, 以换行符结束
2.awk开始进行字段分解,每个字段存储在已编号的变量中,从$1开始[默认空格分割]
3.awk默认字段分隔符是由内部FS变量来确定, 可以使用-F修订
4.awk行处理时使用了print函数打印分割后的字段
5.awk在打印后的字段加上空格,因为$1,$3 之间有一个逗号。逗号被映射至OFS内部变量中,称为输出字段分隔符, OFS默认为空格.
6.awk输出之后,将从文件中获取另一行,并将其存储在$0中,覆盖原来的内容,然后将新的字符串分隔成字段并进行处理。该过程将持续到所有行处理完毕.

awk简单用法
$NF 最后一列
awk ‘//’
awk '{print $n}'  $NF 最后一列
awk ‘NR==1’ NR>2 && NR <3  取行,固定行和范围行
awk 'END{print NR}' 1.txt  取总行数  END是最后一行
awk 'END{print $0}' passwd.txt  取最后一行
awk -F '[, ]' file  ,和空格都是分隔符 '[, ]+'不但作为分隔符,也可以整体使用
awk '{NR==1 {print $n}}' file   取文件第一行,然后打印出列
awk 'BEGIN{print 1/3}'   对1/3进行运算,相当于计算器
awk '!/str/' file !取反 和sed不一样,放在匹配的前面
df |awk '/\/$/ {if ($3>50000) print $4}' 判断大于多少则输出什么内容 command |awk 'pattern {action}'
awk '{print $0}' /etc/passwd  $0保存当前记录的内容
awk '{print FNR,$0}' /etc/passwd /etc/hosts  2个文件分别的行号都输出
awk '{print NR,$0}' /etc/passwd /etc/hosts   2个文件的行号叠加
awk -F'[ :\t]' '{print $1,$2,$3}' /etc/passwd  以空格冒号tab作为字段分割
### OFS指定输出字段分隔符
### 逗号映射为OFS, 初始情况下OFS变量是空格
awk -F: '/root/{print $1,$2,$3,$4}' /etc/passwd
awk 'BEGIN{FS=":"; OFS="+++"} /^root/{print $1,$2}' /etc/passwd
awk -F: 'BEGIN{RS=" "} {print $0}' /etc/hosts  RS输入记录分隔符,默认为换行符,将空格换成了换行 RS=" ",RS是换行
[root@Shell ~]# awk -F: 'BEGIN{ORS=" "} {print $0}' /etc/hosts ORS将文件以空格为分割每一行合并为一行[了解]
printf 函数
awk -F: '{printf "%-15s %-10s %-15s\n", $1, $2, $3}' /etc/passwd
%s 字符类型
%d 数值类型
占 15 字符

表示左对齐,默认是右对齐
printf 默认不会在行尾自动换行,加\n

Awk模式动作
awk语句都由模式和动作组成。
模式部分决定动作语句何时触发及触发事件。
如果省略模式部分,动作将时刻保持执行状态。模式可以是条件语句或复合语句或正则表达式。

1.正则表达式
匹配记录(整行)
[root@Shell ~]# awk '/^root/' /etc/passwd
[root@Shell ~]# awk '$0 ~ /^root/' /etc/passwd

匹配字段:匹配操作符(~ !~)
[root@Shell ~]# awk '$1~/^root/' /etc/passwd
[root@Shell ~]# awk '$NF !~ /bash$/' /etc/passwd

2.比较表达式
比较表达式采用对文本进行比较,只有当条件为真,才执行指定的动作。
比较表达式使用关系运算符,用于比较数字与字符串。

运算符     含义         示例 
 
<       小于          x<y 
 
<=      小于或等于     x<=y 
 
==      等于          x==y 
 
!=      不等于         x!=y
>=      大于等于        x>=y
>       大于          x>y

uid为0的列出来
[root@Shell ~]# awk -F ":" '$3==0' /etc/passwd

uid小于10的全部列出来
[root@Shell ~]# awk -F: '$3 < 10' /etc/passwd

用户登陆的shell等于/bin/bash
[root@Shell ~]# awk -F: '$7 == "/bin/bash" ' /etc/passwd

第一列为alice的列出来
[root@Shell ~]# awk -F: '$1 == "alice" ' /etc/passwd

为alice的用户列出来
[root@Shell ~]# awk -F: '$1 ~ /alice/ ' /etc/passwd
[root@Shell ~]# awk -F: '$1 !~ /alice/ ' /etc/passwd

磁盘使用率大于多少则,则打印可用的值
[root@Shell ~]# df |awk '/\/$/'|awk '$3>1000000 {print $4}'

3.条件表达式
[root@Shell ~]# awk -F: '$3>300 {print $0}' /etc/passwd
[root@Shell ~]# awk -F: '{if($3>300) print $0}' /etc/passwd
[root@Shell ~]# awk -F: '{if($3>5555){print $3} else {print $1}}' /etc/passwd

4.运算表达式

[root@Shell ~]# awk -F: '$3 * 10 > 500000' /etc/passwd
[root@Shell ~]# awk -F: 'BEGIN{OFS="--"} { if($3*10>50000) {print $1,$3} } END {print "打印ok"}' /etc/passwd
[root@Shell ~]# awk '/southem/{print $5 + 10}' datafile 
[root@Shell ~]# awk '/southem/{print $5 + 10.56}' datafile
[root@Shell ~]# awk '/southem/{print $8 - 10}' datafile 
[root@Shell ~]# awk '/southem/{print $8 / 2 }' datafile  
[root@Shell ~]# awk '/southem/{print $8 * 2 }' datafile 
[root@Shell ~]# awk '/southem/{print $8 % 2 }' datafile

5.逻辑操作符和复合模式
&&逻辑与 || 逻辑或 !逻辑非
匹配用户名为root并且打印uid小于15的行
[root@Shell ~]# awk -F: '$1~/root/ && $3<=15' /etc/passwd

匹配用户名为root或uid大于5000
[root@Shell ~]# awk -F: '$1~/root/ || $3>=5000' /etc/passwd

统计系统用户数量
[root@Shell ~]# awk -F: '{ if($3>0 && $3<1000){i++}} END {print i}' /etc/passwd
统计普通用户数量
[root@Shell ~]# awk -F: '{ if($3>1000){i++}} END {print i}' /etc/passwd

Awk循环语句

[root@Shell ~]# awk 'BEGIN{ i=1; while(i<=10){print i; i++} }'
[root@Shell ~]# awk -F: '{i=1; while(i<=NF){print $i; i++}}' /etc/passwd
[root@Shell ~]# awk -F: '{i=1; while(i<=10) {print $0; i++}}' /etc/passwd
[root@Shell ~]#cat b.txt
111 222
333 444 555
666 777 888 999
[root@Shell ~]# awk '{i=1; while(i<=NF){print $i; i++}}' b.txt
1.4.11.2    for循环
C 风格 for
[root@Shell ~]# awk 'BEGIN{for(i=1;i<=5;i++){print i} }' 
将每行打印 10 次
[root@Shell ~]# awk -F: '{ for(i=1;i<=10;i++) {print $0} }' passwd
[root@Shell ~]# awk -F: '{ for(i=1;i<=10;i++) {print $0} }' passwd 
[root@Shell ~]# awk -F: '{ for(i=1;i<=NF;i++) {print $i} }' passwd

awk数组概述

统计/etc/passwd中各种类型shell 的数量*
awk -F: '{shells[$NF]++} END{ for(i in shells){print i,shells[i]} }' /etc/passwd
站访问状态统计<当前时实状态ss>*
[root@Shell ~]# ss -an|awk '/:80/{tcp[$2]++} END {for(i in tcp){print i,tcp[i]}}'

统计当前访问的每个IP的数量<当前时实状态 netstat,ss>*
[root@Shell ~]# ss -an|awk -F ':' '/:80/{ips[$(NF-1)]++} END {for(i in ips){print i,ips[i]}}'

Awk数组案例
Nginx日志分析,日志格式如下:
 
log_format  main  '$remote_addr - $remote_user [$time_local] "$request" '
                      '$status $body_bytes_sent "$http_referer" '
                      '"$http_user_agent" "$http_x_forwarded_for"';
 
52.55.21.59 - - [25/Jan/2018:14:55:36 +0800] "GET /feed/ HTTP/1.1" 404 162 "https:www.google.com/" "Opera/9.80 (Macintosh; Intel Mac OS X 10.6.8; U; de) Presto/2.9.168 Version/11.52" "-"
统计2018年01月25日,当天的PV量*
[root@Shell ~]# grep "25/Jan/2018" log.bjstack.log |wc -l
[root@Shell ~]# awk "/25\/Jan\/2018/" log.bjstack.log |wc -l
[root@Shell ~]# awk '/25\/Jan\/2018/ {ips[$1]++} END {for(i in ips) {sum+=ips[i]} {print sum}}' log.bjstack.log
统计15-19点的pv量
[root@Shell ~]# awk '$4>="[25/Jan/2018:15:00:00" && $4<="[25/Jan/2018:19:00:00 {print $0}"' log.bjstack.log |wc -l

统计2018年01月25日,一天内访问最多的10个IP*
[root@Shell ~]# awk '/25\/Jan\/2018/ {ips[$1]++} END {for(i in ips){ print ips[i],i}}' log.bjstack.log |sort -rn|head

统计15-19点访问次数最多的10个IP
[root@Shell ~]# awk '$4>="[25/Jan/2018:15:00:00" && $4<="[25/Jan/2018:19:00:00"' log.bjstack.log |awk '{ips[$1]++} END {for(i in ips){print ips[i],i}}'|sort -rn|head

统计2018年01月25日,访问大于100次的IP*
[root@Shell ~]# awk '/25\/Jan\/2018/ {ips[$1]++} END {for(i in ips){if(ips[i]>10){print i,ips[i]}}}' log.bjstack.log

统计2018年01月25日,访问最多的10个页面($request top 10)*
[root@Shell ~]# awk '/25\/Jan\/2018/ {request[$7]++} END {for(i in request){print request[i],i}}' log.bjstack.log |sort -rn|head

统计2018年01月25日,每个URL访问内容总大小($body_bytes_sent)*
[root@Shell ~]# awk '/25\/Jan\/2018/ {request[$7]++;size[$7]+=$10} END {for(i in request){print request[i],i,size[i]}}' log.bjstack.log |sort -rn|head

统计2018年01月25日,每个IP访问状态码数量($status)*
[root@Shell ~]# awk '{ip_code[$1 " " $9]++} END {for(i in ip_code){print ip_code[i],i}}' log.bjstack.log|sort -rn|head

统计2018年01月25日,访问状态码为404及出现的次数($status)*
[root@Shell ~]# grep "404" log.bjstack.log |wc -l
[root@Shell ~]# awk '{if($9=="404") code[$9]++} END {for(i in code){print i,code[i]}}' log.bjstack.log

统计2018年01月25日,8:30-9:00访问状态码是404*
[root@Shell ~]# awk '$4>="[25/Jan/2018:15:00:00" && $4<="[25/Jan/2018:19:00:00" && $9=="404" {code[$9]++} END {for(i in code){print i,code[i]}}' log.bjstack.log
[root@Shell ~]# awk '$9=="404" {code[$9]++} END {for(i in code){print i,code[i]}}' log.bjstack.log

统计2018年01月25日,各种状态码数量,统计状态码出现的次数
[root@Shell ~]# awk '{code[$9]++} END {for(i in code){print i,code[i]}}' log.bjstack.log
[root@Shell ~]# awk '{if($9>=100 && $9<200) {i++}
else if ($9>=200 && $9<300) {j++}
else if ($9>=300 && $9<400) {k++}
else if ($9>=400 && $9<500) {n++}
else if($9>=500) {p++}}
END{print i,j,k,n,p,i+j+k+n+p}' log.bjstack.log

posted @ 2020-08-25 11:11  大葱丁  阅读(158)  评论(0编辑  收藏  举报