首先我们现在知道Linux下一切皆文件,对Linux的操作就是对文件的处理,那么怎么能更好的处理文件呢?这就要用到我们上面的三剑客命令。
在说这三个命令前我们要插入一个小插曲就是“正则表达式”。
目录
正则表达与三剑客的说明
所谓的正则表达式我个人理解就是正规的表示方法。他是用简单的方法来实现强大的功能,所以深受计算机爱好者的使用。
三剑客与正则表达式是什么关系呢?
我们可以这样理解,三剑客就是普通的命令,有的把他们叫做工具,在我看来都一样。而正则表达式就好比一个模版。三剑客能读懂这个模版。就这么简单。
三剑客:
1.grep文本搜索工具(过滤匹配的行)
Linux系统中grep命令是一种强大的文本搜索工具,它能使用正则表达式搜索文本,并把匹配的行打印出来。grep全称是Global Regular Expression Print,表示全局正则表达式版本,它的使用权限是所有用户。
2.sed流式编辑器 逐行处理
对文档进行非交互式增删改查的操作
3.awk精确搜索 (二次处理)
简单来说,awk就是把文件逐行读入,以空格为默认分隔符将每行切片,然后可以对切开的部分进行各种处理。相对于grep的查找、匹配和sed的编辑,awk适合对文本进行较复杂的格式处理。
三剑客的对比:
grep:文本过滤器,如果仅仅是过滤文本,可使用grep,其效率要比其他的高很多
sed:Stream EDitor,流编辑器,默认只处理模式空间,不处理原数据,如果你处理的数据是针对行进行处理的,可以使用sed
awk:报告生成器,格式化以后显示。如果对处理的数据需要生成报告之类的信息,或者你处理的数据是按列进行处理的,最好使用awk
正则表达式是一个模版,这个模版是由一些普通字符和一些元字符组成。普通字符包括大小写的字母和数字,而元字符具有特殊的含义。具体如下
元字符 补充
grep
grep过滤工具
---格式:grep 【选项】 “正则表达式“ 文件
egrep 过滤工具
---格式:egrep 【选项】 “扩展正则表达式“ 文件
举例子:
head -5 /etc/passwd > user //准备素材
grep ^root user //找以root开头的行
grep bash$ user //找以bash结尾的行
grep ^$ user //找空行
grep -v ^$ user //显示除了空行的内容
grep "[root]" user //找rot任意一个字符
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 "[a-Z0-9]" user //找所有字母和数字
grep "[^a-Z0-9]" 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\{2,\}t" user //找rt,中间的o可以有2个以及2个以上
grep "ro\{1,\}t" user //找rt,中间的o可以有1个以及1个以上
grep "ro\{3,\}t" user //找rt,中间的o可以有3个以及3个以上
grep "ro\{2\}t" user //找rt,中间的o必须只有有2个
grep "ro\{1\}t" user //找rt,中间的o必须只有有1个
grep "ro\{3\}t" user //找rt,中间的o必须只有有3个
grep "\(0:\)\{2\}" user //找连续的2个0: 小括号的作用是将字符组合为一个整体
以上命令均可以加-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 "ro\{0,1\}t" user //使用基本正则找o出现0~1次
egrep "ro{0,1}t" user //使用扩展正则,效果同上,比较精简
egrep "ro?t" user //使用扩展正则,效果同上,最精简
egrep "root|^bin" user //找有root或者以bin开头的行
#此时的egrep与grep -E相同
#单词边界
cat aa //素材文件,里面有一些"the"
the
there
the6
the_
123the
egrep "the\b" aa //在aa文件中找the,右边不允许出现数字、字母、下划线
egrep "\bthe\b" aa //找the,两边都不允许出现数字、字母、下划线
grep正则表达式练习
先在regular_express.txt写入内容.... 1,过滤包含 the 关键字 grep -n 'the' regular_express.txt 2,过滤不包含 the 关键字 grep -vn 'the' regular_express.txt 3,过滤不论大小写 the 关键字 grep -in 'the' regular_express.txt 4,过滤 test 或 taste 这两个单字 grep -n 't[ae]st' regular_express.txt 5,过滤有 oo 的字节 grep -n 'oo' regular_express.txt 6,过滤不想要 oo 前面有 g 的 grep -n '[^g]oo' regular_express.txt 7,过滤 oo 前面不想有小写字节 grep -n '[^a-z]oo' regular_express.txt. 8,过滤有数字的那一行 grep -n '[0-9]' regular_express.txt 9,过滤以 the 开头的 grep -n '^the' regular_express.txt 10,过滤以小写字母开头的 grep -n '^[a-z]' regular_express.txt 11,过滤开头不是英文字母 grep -n '^[^a-zA-Z]' regular_express.txt 12,过滤行尾结束为小数点.那一行 grep -n '\.$' regular_express.txt 13,过滤空白行 grep -n '^$' regular_express.txt 14,过滤出 g??d 的字串 grep -n 'g..d' regular_express.txt 15,过滤至少两个 o 以上的字串 grep -n 'ooo*' regular_express.txt 16,过滤 g 开头和 g 结尾但是两个 g 之间仅存在至少一个 o grep -n 'goo*g' regular_express.txt 17,过滤两个 o 的字串 grep -n 'o\{2\}' regular_express.txt 18,过滤 g 后面接 2 到 5 个 o,然后在接一个 g 的字串 grep -n 'go\{2,5\}g' regular_express.txt 19,过滤 g 后面接 2 个以上 o 的 grep -n 'go\{2,\}g' regular_express.txt grep "bash$" /etc/passwd | sed 's/:.*//' //找到以bash结尾的用户 再用sed去掉用户后面:开始的所有内容,留下的就是用户名
sed
用法1:前置命令 | sed [选项] '条件指令'
用法2:sed [选项] '条件指令' 文件.. ..
选项: -n 屏蔽默认输出 -r 支持扩展正则 -i 修改源文件
指令: p 输出 d 删除 s替换 a行下追加 i行上添加 c替换整行
以下列子中的文件内容可以自己写入如
:head /etc/passwd > user
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 '2,+1p' user //输出第2行以及后面1行
sed -n '/^root/p' user //输出以root开头的行
sed -n '/root/p' user //输出包含root的行
sed -nr '/^root|^bin/p' user
将以上语句中的p指令改为d指令可以实现对应行的删除效果
比如sed -n '2p' user 改成 sed '2d' user 是删除第2行
sed -n '2!p' user //输出除了第2行的内容,加!是取反效果
sed '3,+1!d' user //删除第3行、第4行以外的行
sed -n '=' user //显示行号,=号在sed中可以显示行号
sed -n '$=' user //查看文档最后一行的行号,相当于查看文档总行数
sed -i '$d' user //删除文档的最后一行并保存
sed 's/2017/6666/' test.txt //把所有行的第1个2017替换成6666
sed 's/2017/6666/2' test.txt //把所有行的第2个2017替换成6666
sed '1s/2017/6666/' test.txt //把第1行的第1个2017替换成6666
sed '3s/2017/6666/3' test.txt //把第3行的第3个2017替换成6666
sed '3s/2017//3' test.txt //把第3行的第3个2017替换成空,相当
于删除
sed '/2024/s/2017/6666/' test.txt //找到有2024的行,将2017替换
成6666
尝试将user文档中/bin/bash替换成/sbin/sh
sed '1s//bin/bash//sbin/sh/' user //直接替换,报错
sed '1s/\/bin\/bash/\/sbin\/sh/' user //使用转义符号可以
成功,但不方便
sed '1s!/bin/bash!/sbin/sh!' user //最佳方案,更改s的替换符
sed '1s@/bin/bash@/sbin/sh@' user //替换符号可以用所有
数字键上的
sed 's/[0-9]//g' nssw.txt
sed 's/.//2;s/.$echo abc > abc //创建素材
sed -r 's/(a)(b)(c)/\3\2\1/' abc //替换abc时复制每一个字符,后面替换的内容用\数字粘贴,可以任意调换位置
echo xyz >> xyz //追加内容
sed -r 's/(a)(b)(c)/\3\2\1/' abc //再用之前的方法无法替换第2行
sed -r 's/(.)(.)(.)/\3\2\1/' abc //将具体字符用 . 替代即可,然后,再将追加abcd时,上述方案失灵
sed -r 's/^(.)(.*)(.)$/\3\2\1/' abc //再次升级,分别找到第1个字符和最后1个字符,中间可以是任意
sed -r 's/^(.)(.*)(.)$/\3\2\1/' nssw.txt //达成需求
//' test
sed -r 's/([A-Z])/(\1)/g' nssw.txt //先找到任意大写字母,然后保留,最后替换成带括号的状态
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
sed -n '/bash$/s/:.*//p' /etc/passwd //用sed找到以bash结尾的用户
然后去掉用户后面:开始的所有内容,最后加p的作用是仅仅显示被
替换的行
awk
格式1:前置指令 | awk [选项] '[条件]{指令}'
格式2:awk [选项] '[条件]{指令}' 文件
指令:
print 输出
选项:
-F 定义分隔符
内置变量:
$1第1列 $2第2列 $3 ... $0所有列 NR行号 NF列号 awk '{print $1}' test.txt //输出所有行的第1列
使用正则
~包含 !~不包含
使用数字或者字符串
== != >= > <= <
逻辑组合
&&并且 ||或者
运算
/ * % + - .......
awk执行额外任务
BEGIN{ } 执行1次,读取文档之前执行
逐行任务 执行n次 ,读取文档时执行
END{ } 执行1次,读取文档之后执行
简单的例子:
awk '{print $1}' test.txt //输出所有行的第1列
awk '{print $3}' test.txt //输出所有行的第3列
awk '/the/{print $3}' test.txt //输出有the的行的第3列
awk '/the/{print NR}' test.txt //输出有the的行的行号
awk '{print NR}' test.txt //输出所有行的行号
awk '{print NF}' test.txt //输出所有行的列号
awk '{print $0,NR}' test.txt //输出所有列然后空格输出行号
head -5 /etc/passwd > user
awk -F: '{print $1}' user //使用-F:修改分隔符为冒号,输出第1列
awk -F: '{print $1,$7}' user //使用-F:修改分隔符为冒号,输出第1列空格第7列
awk -F: '{print $1,"的解释器是",$7}' user //输出常量加引号
ifconfig eth0 | awk '/RX p/{print "服务器eth0网卡的接收流量是"$5"字节"}'
ifconfig eth0 | awk '/TX p/{print "服务器eth0网卡的发送流量是"$5"字节"}'
df -h | awk '/\/$/{print "根分区剩余容量是"$4}'
awk -F: '$6~/bin/{print}' user //找第6列包含bin的行
awk -F: '$6!~/bin/{print}' user //找第6列不包含bin的行
awk -F: 'NR==1{print}' user //输出第1行
awk -F: 'NR!=3{print}' user //输出除了第3行以外的行
awk -F: 'NR<4{print}' user //输出1~3行
awk -F: '$1=="root"{print}' user //输出第1列等于root的行
awk -F: '$1~/root/{print}' user //输出第1列包含root的行
wk -F: '$3<10&&$7~/bash/' /etc/passwd //输出第3列(UID)小于10并且
第7列包含bash的行,当给了条件输出一整行时{print}可以省略不写
awk -F: 'NR>=2&&NR<=6' /etc/passwd //输出2~6行
awk -F: '$1~/root/||$3<=5' /etc/passwd //输出第1列包含root或者UID小
于等于5的行
awk 'NR%2==0' user //输出偶数行
awk 'BEGIN{ }{ }END{ }' //使用时基本框架
awk 'BEGIN{print "xyz"}{print "xyz"}END{print "xyz"}' user //输出1
个xyz之后再根据user文档的行数输出5个xyz,最后再输出一个xyz
awk 'BEGIN{print "User\tUID\tHome"}' //输出表头信息
awk -F: '{print $1"\t"$3"\t"$6}' user //输出内容,用户名,uid,家目录
awk 'END{print "总计"NR"行"}' user //最后输出行数
awk -F: 'BEGIN{print "User\tUID\tHome"}{print $1"\t"$3"\t"$6}
END{print "总计"NR"行"}' user
awk '{print $1}' /var/log/httpd/access_log //可以找出访问者的ip,但是效果不完美,可以用后面的数组方式解决
awk,for,if循环实现高级搜索
awk 中使用if单分支,如果满足条件,就执行指令,不满足就不执行任何指令
if(条件){指令}
awk -F: 'BEGIN{x=0}{if($7~/bash/){x++}}END{print x}' /etc/passwd
#####统计系统中,有多少用户使用了bash,首先定义变量x,然后使用if判断如果每找到一行的$7包含bash,就把x+1,所有逐行任务结束后,最终使用end任务输出x的值,也就是找系统中使用bash作为解释器的用户数量
双分支,如果满足条件就执行指令,不满足就执行else后面的指令 if(条件){指令}else{指令}
awk -F: 'BEGIN{x=0;y=0}{if($7=="/bin/bash"){x++}else{y++}}END{print x,y}' /etc/passwd
//统计系统中使用bash作为解释器的用户,和没有使用bash的用户数量,使用if判断如果每找到一行的$7是/bin/bash,就把x+1,否则y+1,最后使用end输出x与y的值
多分支 {if (条件){指令}else if (条件){指令}else{指令}}
awk -F: '{if($7=="/bin/bash"){x++}else
if($7=="/sbin/nologin"){y++}else{z++}}END{print x,y,z}' /etc/passwd
//统计系统中使用bash作为解释器的用户,使用nologin的用户,还有其他用户的数量,变量如果作为运算使用,并且初始值是0的 ,可以省略定义过程
数组可以用来收集信息
for循环可以循环输出数组的下标
cat abc.txt
a[abc]=0 a[abc]++ a[abc]=1
a[xyz]=0 a[xyz]++ a[xyz]=1
a[abc]=1 a[abc]++ a[abc]=2
awk '{a[$1]++}END{print a["abc"],a["xyz"]}' abc.txt //根据上述结果,得到如果
使用{a[$1]++}走完所有行便可收集到a[xyz]=1和a[abc]=2的结果,所以
在最后使用END任务输出a[abc]和a[xyz]的值就是 2和 1
awk '{a[$1]++}END{for(i in a){print i,a[i]}}' abc.txt //使用for循环,循环显示
数组a的下标,与值,其中for(i in a)里面的i是变量,代表下标,in是语法不
能变,a是数组名
awk '{a[$1]++}END{for(i in a){print i,a[i]}}' /var/log/httpd/access_log //将上述
的abc.txt文件替换成网站的日志,就可以最终用来查看日志得到可以得到
哪个ip来访以及来访的次数
awk '{ip[$1]++}END{for(i in ip){print ip[i],i} }' /var/log/httpd/access_log | sort -nr
查看日志中某个ip的出现次数,以及ip,然后按降序排列,出现次数最大的
显示在第一行,sort命令可以实现排序效果,-n是以数字排序,-r是降序
awk '/Failed password for root/{ip[$11]++}END{for(i in ip){print ip[i],i}}' /var/log/secure
//查看哪个ip登录root账户时输入错了密码,先输出次数,再输出ip