正则表达式
可以使用若干符号配合某工具对字符串进行增删改查操作
head -5 /etc/passwd > user //准备素材
一、grep
grep ^root user //找以root开头的行
grep bash$ user //找以bash结尾的行
grep ^$ user //找空行
grep -v ^$ user //显示除了空行的内容
grep "[root]" user //找r、o、t任意一个字符
grep "[rot]" user //效果同上
grep "[^rot]" user //显示r或o或t以外的内容
grep "[0123456789]" user //找所有数字
grep "[0-9]" user //效果同上
grep "[^0-9]" user //显示数字以外内容
grep "[a-z]" user //找所有小写字母
grep "[A-Z]" user //找所有大写字母
grep "[a-Z]" user //找所有字母
grep "[^0-9a-Z]" user //找所有符号
grep "." user //找任意单个字符,文档中每个字符都可以理解为任意字符
grep "r..t" user //找rt之间有2个任意字符的行
grep "r.t" user //找rt之间有1个任意字符的行,没有匹配内容,就无输出
grep "*" user //错误用法,*号是匹配前一个字符任意次,不能单独使用
grep "ro*t" user //找rt,中间的o有没有都行,有几次都行
grep ".*" user //找任意,包括空行 .与*的组合在正则中相当于通配符的效果
grep "ro\{1,2\}t" user //找rt,中间的o可以有1~2个
grep "ro\{2,6\}t" user //找rt,中间的o可以有2~6个
grep "ro\{1,\}t" user //找rt,中间的o可以有1个以及1个以上
grep "ro\{3\}t" user //找rt,中间的o必须只有有3个
以上命令均可以加-E选项并且去掉所有\,改成扩展正则的用法,比如
grep "ro\{1,\}t" user
可以改成
grep -E "ro{1,}t" user
或者
egrep "ro{1,}t" user
grep "ro\{1,\}t" user //使用基本正则找o出现1次以及1次以上
egrep "ro{1,}t" user //使用扩展正则,效果同上,比较精简
egrep "ro+t" user //使用扩展正则,效果同上,最精简
grep "roo\{0,1\}t" user //使用基本正则找第二个o出现0~1次
egrep "roo{0,1}t" user //使用扩展正则,效果同上,比较精简
egrep "roo?t" user //使用扩展正则,效果同上,最精简
egrep "(0:){2}" user //找连续的2个0: 小括号的作用是将字符组合为一个整体
egrep "root|bin" user //找有root或者bin的行
egrep "the\b" abc.txt //在abc.txt文件中找the,右边不允许出现数字、字母、下划线
egrep "\bthe\b" abc.txt //两边都不允许出现数字、字母、下划线
egrep "\<the\>" abc.txt //效果同上
二、sed
流式编辑器
可以对文档进行非交互式增删改查,逐行处理
用法:
| sed 选项 条件 指令
sed 被处理文档
选项 -n 屏蔽默认输出 -r 支持扩展正则 -i 修改源文件
指令 p 输出 d 删除 s 替换
条件 行号 //
-e<script>或--expression=<script>:以选项中的指定的script来处理输入的文本文件;
-f<script文件>或--file=<script文件>:以选项中指定的script文件来处理输入的文本文件;
-h或--help:显示帮助;
-n或--quiet或——silent:仅显示script处理后的结果;
-V或--version:显示版本信息。
sed命令
a\ # 在当前行下面插入文本。
i\ # 在当前行上面插入文本。
c\ # 把选定的行改为新的文本。
d # 删除,删除选择的行。
D # 删除模板块的第一行。
s # 替换指定字符
h # 拷贝模板块的内容到内存中的缓冲区。
H # 追加模板块的内容到内存中的缓冲区。
g # 获得内存缓冲区的内容,并替代当前模板块中的文本。
G # 获得内存缓冲区的内容,并追加到当前模板块文本的后面。
l # 列表不能打印字符的清单。
n # 读取下一个输入行,用下一个命令处理新的行而不是用第一个命令。
N # 追加下一个输入行到模板块后面并在二者间嵌入一个新行,改变当前行号码。
p # 打印模板块的行。
P # (大写) 打印模板块的第一行。
q # 退出Sed。
b lable # 分支到脚本中带有标记的地方,如果分支不存在则分支到脚本的末尾。
r file # 从file中读行。
t label # if分支,从最后一行开始,条件一旦满足或者T,t命令,将导致分支到带有标号的命令处,或者到脚本的末尾。
T label # 错误分支,从最后一行开始,一旦发生错误或者T,t命令,将导致分支到带有标号的命令处,或者到脚本的末尾。
w file # 写并追加模板块到file末尾。
W file # 写并追加模板块的第一行到file末尾。
! # 表示后面的命令对所有没有被选定的行发生作用。
= # 打印当前行号码。
# # 把注释扩展到下一个换行符以前。
sed替换标记
g # 表示行内全面替换。
p # 表示打印行。
w # 表示把行写入一个文件。
x # 表示互换模板块中的文本和缓冲区中的文本。
y # 表示把一个字符翻译为另外的字符(但是不用于正则表达式)
\1 # 子串匹配标记
& # 已匹配字符串标记
sed元字符集
^ # 匹配行开始,如:/^sed/匹配所有以sed开头的行。
$ # 匹配行结束,如:/sed$/匹配所有以sed结尾的行。
. # 匹配一个非换行符的任意字符,如:/s.d/匹配s后接一个任意字符,最后是d。
* # 匹配0个或多个字符,如:/*sed/匹配所有模板是一个或多个空格后紧跟sed的行。
[] # 匹配一个指定范围内的字符,如/[sS]ed/匹配sed和Sed。
[^] # 匹配一个不在指定范围内的字符,如:/[^A-RT-Z]ed/匹配不包含A-R和T-Z的一个字母开头,紧跟ed的行。
\(..\) # 匹配子串,保存匹配的字符,如s/\(love\)able/\1rs,loveable被替换成lovers。
& # 保存搜索字符用来替换其他字符,如s/love/ **&** /,love这成 **love** 。
\< # 匹配单词的开始,如:/\<love/匹配包含以love开头的单词的行。
\> # 匹配单词的结束,如/love\>/匹配包含以love结尾的单词的行。
x\{m\} # 重复字符x,m次,如:/0\{5\}/匹配包含5个0的行。
x\{m,\} # 重复字符x,至少m次,如:/0\{5,\}/匹配至少有5个0的行。
x\{m,n\} # 重复字符x,至少m次,不多于n次,如:/0\{5,10\}/匹配5~10个0的行。
sed用法实例
替换操作:s命令
替换文本中的字符串:
sed 's/book/books/' file
-n选项 和 p命令 一起使用表示只打印那些发生替换的行:
sed -n ‘s/test/TEST/p’ file
直接编辑文件 选项-i ,会匹配file文件中每一行的所有book替换为books:
sed -i 's/book/books/g' file
全面替换标记g
使用后缀 /g 标记会替换每一行中的所有匹配:
sed 's/book/books/g' file
当需要从第N处匹配开始替换时,可以使用 /Ng:
echo sksksksksksk | sed 's/sk/SK/2g'skSKSKSKSKSK
echo sksksksksksk | sed 's/sk/SK/3g'skskSKSKSKSK
echo sksksksksksk | sed 's/sk/SK/4g'skskskSKSKSK
定界符
以上命令中字符 / 在sed中作为定界符使用,也可以使用任意的定界符:
sed 's:test:TEXT:g'sed 's|test|TEXT|g'
定界符出现在样式内部时,需要进行转义:
sed 's/\/bin/\/usr\/local\/bin/g'
删除操作:d命令
删除空白行:
sed '/^$/d' file
删除文件的第2行:
sed '2d' file
删除文件的第2行到末尾所有行:
sed '2,$d' file
删除文件最后一行:
sed '$d' file
删除文件中所有开头是test的行:
sed '/^test/'d file
sed -n 'p' user //输出所有行
sed -n '1p' user //输出第1行
sed -n '2p' user //输出第2行
sed -n '3p' user //输出第3行
sed -n '2,4p' user //输出2~4行
sed -n '2p;4p' user //输出第2行与第4行
sed -n '3,+1p' user //输出第3行以及后面1行
sed -n '/^root/p' user //输出以root开头的行
sed -n '/root/p' user //输出包含root的行
sed -nr '/^root|^bin/p' user //输出以root开头的行或bin开头的行,|是扩展正则,需要r选项
sed -n '1!p' user //输出除了第1行的内容,!是取反
sed -n '$p' user //输出最后一行
sed -n '=' user //输出行号,如果是$=就是最后一行的行号
以上操作,如果去掉-n,在将p指令改成d指令就是删除
输出所有行 sed -n ‘p’ abc.txt
输出第4行 sed -n ‘4p’ abc.txt
输出第4~7行 sed -n ‘4,7p’ abc.txt
输出以bin开头的行 sed -n ‘/^bin/p’ abc.txt
输出文件的总行数 sed -n ‘$=’ abc.txt
删除第3~5行 sed ‘3,5d’ abc.txt
删除所有包含xml的行 sed ‘/xml/d’ abc.txt
删除不包含xml的行 sed ‘/xml/!d’ abc.txt
删除以install开头的行 sed ‘/^install/d’ abc.txt
删除文件的最后一行 sed ‘$d’ abc.txt
删除所有空行 sed ‘/^$/d’ abc.txt
替换
sed 's/2017/6666/' shu.txt //把所有行的第1个2017替换成6666
sed 's/2017/6666/2' shu.txt //把所有行的第2个2017替换成6666
sed '1s/2017/6666/' shu.txt //把第1行的第1个2017替换成6666
sed '3s/2017/6666/3' shu.txt //把第3行的第3个2017替换成6666
sed 's/2017/6666/g' shu.txt //所有行的所有个2017都替换
sed '/2024/s/2017/6666/g' shu.txt //找含有2024的行,将里面的所有2017替换成6666
如果想把 /bin/bash 替换成 /sbin/sh 怎么操作?
sed -i '1s/bin/sbin/' user //传统方法可以一个一个换,先换一个
sed -i '1s/bash/sh/' user //再换一个
如果想一起一步替换:
sed 's//bin/bash//sbin/sh/' user //直接替换,报错
sed 's/\/bin\/bash/\/sbin\/sh/' user //使用转义符号可以成功,但不方便
sed 's!/bin/bash!/sbin/sh!' user //最佳方案,更改s的替换符
sed 's(/bin/bash(/sbin/sh(' user //替换符号可以用所有数字键上的
sed其他指令补充
a行下追加 i行上添加 c替换整行
sed 'a 666' user //所有行的下面追加666
sed '1a 666' user //第1行的下面追加666
sed '/^bin/a 666' user //在以bin开头的行的下面追加666
sed 'i 666' user //所有行的上面添加666
sed '5i 666' user //第5行的上面添加666
sed '$i 666' user //最后1行的上面添加666
sed 'c 666' user //所有行都替换成666
sed '1c 666' user //替换第1行为666
三、awk
awk
可以实现精确搜索并输出 ,逐行处理
1,前置指令 | awk 选项 条件 指令
2,awk 选项 条件 指令 被处理文档
选项 -F 定义分隔符
指令 print
条件 /字符串/
内置变量 $1第一列 $2第二列 $3第三列 …
$0 所有列 NR行号 NF 列号
[root@proxy opt]# cat abc.txt //准备素材
hello the world
welcome to beijing
awk '{print}' abc.txt //输出所有
awk '/to/{print}' abc.txt //输出有to的那行
awk '{print $2}' abc.txt //输出所有行的第2列
awk '/to/{print $1}' abc.txt //输出有to的那行的第1列
awk '{print $0}' abc.txt //输出所有行所有列
awk '{print $0,$1}' abc.txt //输出所有行所有列,第1列
awk '{print NR}' abc.txt //输出所有行的行号
awk '{print NR,$0}' abc.txt //输出所有行的行号,所有列
awk '{print NR,NF}' abc.txt //输出所有行的行号,列号(有几列)
awk '/^bin/{print NR}' user //找以bin开头的行,显示该行的行号
awk '/^bin/{print NR,$0}' user //找以bin开头的行,显示该行的行号,所有列
awk '{print NF}' user //输出所有行的列号(每行有几列)
awk -F: '{print $1}' user //文档中如果没有空格,可以用F修改分隔符
awk -F: '{print $1,$6}' user //使用冒号作为列的分隔符,显示第1、6列
awk -F: '{print $1" 的家目录是 "$6}' user //还可以输出常量,加双引号即可
awk -F: '{print $1" 的解释器是 "$7}' user
收集根分区剩余容量
df -h | awk '/\/$/{print $4}' //使用df -h 作为前置指令交给awk处理找到以/结尾的行,并输出第4列
df -h | awk '/\/$/{print "根分区剩余容量是"$4}' //然后加常量输出
收集网卡流量信息
ifconfig eth0 | awk '/RX p/{print "eth0网卡接收的数据量是"$5"字节"}'
ifconfig eth0 | awk '/TX p/{print "eth0网卡发送的数据量是"$5"字节"}'
awk的条件
1,/字符串/ 还可以使用正则 ~ 包含 !~不包含
awk -F: '$6~/root/{print}' user //输出第6列包含root的行
awk -F: '$6~/bin/{print}' user //输出第6列包含bin的行
awk -F: '$6!~/bin/{print}' user //输出第6列不包含bin的行
2,使用数字或者字符串
== != > >= < <=
awk -F: '$3<3{print}' user //输出第3列小于3的行
awk -F: '$3<=3{print}' user //输出第3列小于等于3的行
awk -F: 'NR==2{print}' user //输出第2行
awk -F: 'NR>2{print}' user //输出行号大于2的行
3,逻辑组合 &&并且 ||或者
awk -F: 'NR==2||NR==4{print}' user //找行号是2或者4的行
awk -F: 'NR==2||NR==40{print}' user //如果只有一个条件满足就显示一个
awk -F: '$7~/bash/&&$3<=500{print}' user //找第7列包含bash并且第3列小于等于500的
awk 'NR==2&&NR==4{print}' user //找行号既是2又是4的行,不存在,无输出
awk -F: '$7~/bash/&&NR<=3{print}' user //找第7列包含bash并且行号是1~3的
awk -F: '$7~/bash/||NR<=3{print}' user //找第7列包含bash或者行号是1~3的
awk -F: '$1~/root/' user //找第1列包含root的行如果有用户叫root6,也会搜到,比较宽松的搜索方式,如果任务就是{print}的话可以省略不写
awk -F: '$1=="root"' user //找第1列完全等于root的行多一个字符少一个字符都不行,比较严格的搜索方式
4,运算
awk 'NR%2==0{print NR,$0}' user //在条件中使用运算,找到将行号除以2余数等于0的行,然后输出该行的行号和所有列,相当于输出偶数行
awk处理时机,可以执行额外任务
BEGIN任务 执行1次,读取文档之前执行
逐行任务 执行n次,读取文档时执行
END任务 执行1次,读取文档之后执行
BEGIN{ 任务1 }{ 任务2 }END
awk -F: 'BEGIN{print "ok"}{print $1}END{print "ok"}' user
awk 'BEGIN{print NR}{print NR}END{print NR}' user
利用awk处理时机,输出下列内容
awk 'BEGIN{print "User\tUID\tHome"}' //第1步输出表头信息
awk -F: '{print $1"\t"$3"\t"$6}' user //第2步输出内容
awk 'END{print "总计"NR"行" }' user //第3步输出结尾
awk -F: 'BEGIN{print "User\tUID\tHome"}{print $1"\t"$3"\t"$6}END{print "总计"NR"行"}' user //合在一起写
使用awk统计网站访问量
setenforce 0 //关闭selinux
systemctl stop firewalld //关闭防火墙
systemctl restart httpd //开启网站服务
使用浏览器多访问几次网站,包括本机用curl
curl 192.168.4.7:82 //如果端口没改过就不用敲
awk '{print $1}' /var/log/httpd/access_log //初步统计,不完美
使用awk数组+for循环实现高级搜索
数组 相当于可以存储多个值的特殊变量
数组名[下标]=下标对应的值
awk 'BEGIN{a[1]=10;a[2]=20;print a[2],a[1]}' //使用awk测试数组,首先创建数组a,下标1对应值是10,下标2对应值是20,然后输出下标是2与下标是1的值
awk 'BEGIN{a["abc"]="abcabc";a["xyz"]="xyzxyz";print a["xyz"]}' //数组的下标和值都可以不是数字,测试时加双引号即可
以上信息是手工输入,实际情况中通常是从文档收集
准备一个文档,里面有6行,每行分别是abc、xyz、abc、opq、xyz、abc 然后
按照awk逐行处理的工作特点使用awk ‘{a[$1]++}’ shu.txt 走完每一行得到下列结果
但不会输出到屏幕
a[$1]++ a[abc]++ a[abc]=1
a[$1]++ a[xyz]++ a[xyz]=1
a[$1]++ a[abc]++ a[abc]=2
a[$1]++ a[opq]++ a[opq]=1
a[$1]++ a[xyz]++ a[xyz]=2
a[$1]++ a[abc]++ a[abc]=3
如果要输出到屏幕可以使用命令awk ‘{a[$1]++}END{print a[“abc”]}’ shu.txt
根据上述操作得知使用数组可以收集信息,但收集完了之后查看确不方便,可以用for循环实现。方法如下:
for(变量名 in 数组名){print 变量名} //这个格式可以查看数组的所有下标
awk '{a[$1]++}END{for(i in a){print i,a[i]}}' shu.txt //使用逐行任务与数组收集文档shu.txt中的信息,然后在END任务中使用for循环显示所有数组a的下标与值
awk '{ip[$1]++}END{for(i in ip){print i,ip[i]}}' /var/log/httpd/access_log //将上述的文件替换成网站的日志,就可以最终用来查看日志得到可以得到哪个ip来访以及来访的次数
awk '{ip[$1]++}END{for(i in ip){print i,ip[i]}}' /var/log/httpd/access_log | sort -nr -k 2 //使用sort命令增加排序功能,-n是以数字形式排序,-r是降序, -k是指定为第几列排序
/var/log/secure是安全日志,如果有人登陆时输入错误密码的话
信息会记录下来,这种信息可以用awk抓取出来,方法如下:
awk '/Failed password for root/{ip[$11]++}END{for(i in ip){print i,ip[i]}}' /var/log/secure //统计安全日志中访问root账户密码输入错误的ip地址与次数
编写脚本,可以查看系统的各种参数信息
#!/bin/bash
while :
do
clear
free -h | awk '/^Mem:/{print "剩余内存容量是"$4}'
df -h | awk '/\/$/{print "根分区剩余容量是"$4}'
awk 'END{print "用户总数是"NR"个"}' /etc/passwd
who | awk 'END{print "登录用户数量是"NR"个"}'
uptime | awk '{print "cpu的15分钟平均负载是"$NF}'
rpm -qa | awk 'END{print "安装的软件包数量是"NR"个"}'
sleep 3
done
评论区