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