04~文本处理三剑客

青春须早为,岂能长少年。这篇文章主要讲述04~文本处理三剑客相关的知识,希望能为你提供帮助。
一、文本行过滤工具grep

  1. grep:按照相应的正则表达式完成目标文本中信息匹配
  2. 以下主要举例常用的一些options;
cat /etc/passwd | grep -v "\\(root\\)" //显示没有匹配到root字符的行
cat /etc/passwd | grep -i "\\(root\\)" //忽略字符大小写
cat /etc/passwd | grep -o "\\(root\\)" //只显示匹配到的root字符
cat /etc/passwd | grep -c "\\(root\\)" //统计匹配到的字符行数
cat /etc/passwd | grep -n "\\(root\\)" //显示匹配到行号
cat /etc/passwd | grep -e "\\(root\\)" -e "\\(user\\)" //可以多个选项按照或的逻辑关系匹配
cat /etc/passwd | grep --color=auto "\\(user\\)" //将匹配到的字符着色显示
cat /etc/passwd | grep -A 3 "\\(user1\\)" //匹配到字符行后3行(不含匹配行),-B 表示前几行,-C表示前后各几行
cat /etc/passwd | grep -E "user1"//-E是扩展正则表达式识别符,等价于egrep
cat /etc/passwd | grep -f /data/f1.txt /data/f2.txt //取两个文件中的相同行

  1. 练习巩固
egrep "^(.*)\\> .*\\< \\1$" /etc/passwd//匹配以任意长度任意字符开头且后面跟了任意长度任意字符,最后以^(.*)即开头的字符出现一次结尾。
grep -E "^(.*)\\> .*\\< \\1$" /etc/passwd //效果同上,\\1表示引用^(.*)一次,\\> .*\\< 表示匹配任意长度任意字符(和.*是等价的)
grep "^\\(.*\\)\\> .*\\< \\1$"/etc/passwd //效果同上,只是用了正则表达式,使用了转义字符\\;
/*注:上述的命令匹配的结果就是用户名和默认的shell的文件夹名字相同*/;
cat /data/test.txt | grep -o "[0-9]\\+" | tr -s \\n +-f1-3 | bc
cat /data/test.txt | grep -Eo "[0-9]+" | tr -s \\n +| grep -Eo ".*[0-9]" | bc
cat /data/test.txt | grep -oE "[0-9]+" | paste -s -d+ | bc
cat /data/test.txt | cut -d "=" -f2 | tr -s \\n + | grep -Eo ".*[0-9]" | bc
//上述指令是完成test.txt中的三个人年龄的求和,\\n是将回车符替换成+,再将其取出1-3行(第4行也是+号,不能取出,bc会报错),最终在使用bc执行
//这个功能实现有很多中方式,按照自己最熟悉的来就可以。paste -s -d 中的-s表示所有行合成一行,-d表示指定分隔符,默认是TAB;

二、文本编辑工具sed
  1. sed从文件和管道中按照一行一行读取数据,读取的一行数据处理完后再读取下一行,所以对于大文件读取时不存在卡顿问题,这也是其和vi、vim文本处理工具的差别。处理每行时,会将当前处理行存储到计算机临时缓冲区(内存中的一部分空间),这个缓冲区称为模式空间(Pattern Space)
  2. 用法归类
【04~文本处理三剑客】  1)基本用法
一、[option]常使用的选项有以下几点:
-n//匹配的内容不会打印到屏幕
-e//多内容编辑,即可以匹配多个内容;
-f FILE //从指定文本中读取脚本script
-r、-E//匹配字符等使用扩展正则表达式
-i.bak//备份文件并在源文件中修改编辑
-s//将多个文件视为独立文件,而不是的那个连续的长文件流
注:不可使用的组合:-ir、-i -r、-ri,另外-ni(会清空文件)

二、script使用方式(可以为三类:地址、命令、查找替代)
1)地址
default//即不指定匹配地址,则对全文进行匹配处理;
#//指定的行,#代表对应的行号
$//最后一行信息
/pattern/ //匹配到的每一行
#,#//表示从第#行到#行
#,+#//表示从第#行到+#行
/part1/,/part2/ //表示从part1一直匹配搭配part2
#,/par/
/part/,#
~//步进符号
1~2//表示奇数行
2~2//表示偶数行
2)命令
p//打印当前模式空间内容,追加到默认输出之后
Ip//忽略大小写输出
d//删除模式空间匹配的行,并立即启动下一轮循环;
a \\text //在指定行后面追加文本,支持使用\\n实现多行追加
i \\text //在指定行前面插入文本
c \\text //将匹配的单行或者多行替换
w file//保存模式匹配的行到指定文件
r file//读取指定文件的文本到模式空间中匹配到的行后面
=//为模式空间中的行打印行号
!//模式空间中匹配的行取反处理
q//结束或退出sed

三、查找替代
s/pattern/替换的字符/命令选项 //其中pattern表示需要查找的字符、命令选项一般都是p
g //行内全局替换
p //显示替换成功的行
w /PATH/FILE //将替换成功的行保存到文件中
I,i //忽略大小写

2)高级用法(保持空间功能)
      sed中除了模式空间、还有保持空间(hold Space),可以将模式空间中的数据临时保存到该空间中,从而后续可以继续处理。
P//打印模式空间开始到\\n内容,并追加到默认输出之前
h//把模式空间中的内容覆盖到保持空间中
H//把模式空间中的内容追加到保持空间中
g//从保持空间中取出数据覆盖到模式空间中
G//从保持空间中取出数据追加到模式空间中
x//把模式空间中的内容与保持空间中的内容进行互换
n//读取匹配到的行的下一行覆盖到模式空间
N//读取匹配到的行的下一行追加到模式空间
d//删除模式空间中的行
D//如果模式空间包含换行符,则删除直到第一个换行符的模式空间中的文本,
//并不会读取新的输入行,而使用合成的模式空间重新启动循环。如果模式
//空间不包含换行符,则会像发出d命令那样启动正常的新循环

3)练习巩固
        下面主要完成一些练习,不一定包含上述中选项中的所有,但可以基本阐述清楚命令以及选项使用方法。
sed/etc/issue//无-n表示默认打印模式空间内容,表示不追加模式空间内容到标准输出。所以只能看到文件中的内容一次;
sed p /etc/issue// 表示对全文处理并输出模式空间内容,并追加到输出之后,所以会打印2遍文件中的内容;
sed -n p /etc/issue//和sed/etc/issue的输出的结果相同,-n表示不打印模式空间内容
sed -n/etc/issue//则什么都打印,-n不显示模式空间内容,中即也默认不追加模式空间内容到标准输出

sed -n 1p /etc/issue//应用了script的地址命令,将模式空间中的第一行内容追加输出;
ifconfig ens33 | sed -n 2p //打印第2行的内容,如果没有-n则会显示ifconfig命令内容;
sed -n $p /etc/issue//显示最后一行信息
ifconfig ens33 | sed -n /netmask/p //匹配/part/内容所在行并显示
df | sed -n /^\\/dev\\/sd/p//显示/dev的分区,^表示行首,\\表示对/dev前的/的转义;

seq 10 | sed -n 3,6p //显示3~6的数字
seq 10 | sed -n 3,+4p//显示3~7的数字
seq 10 | sed -n 3,$p //显示3~最后一行内容,即3~10
seq 10 | sed -n 1~2p //显示奇数
seq 10 | sed -n 2~2p //显示偶数
seq 10 | sed 1~2d //d命令表示删除匹配的奇数行,并立即启动的下轮循环,所以显示偶数
seq 10 | sed 2~2d //同上,显示奇数,-n不能有,是因为有了-n,d命令启动的下轮循环内容也不会显示;
sed -e 2d -e 4d seq.log //-e为可以匹配多条信息且为& 的关系,所以不显示第2、4行外其他均显示;
sed 2d; 4dseq.log//结果同上,两种表达效果;
sed /^#/d; /^$/d /etc/fstab //不显示注释行和空行,^#表示注释行,^$表示空行
grep -Ev ^#|^$ /etc/fstab//同上,grep的-v命令可以显示未匹配到的行,-E表示扩展正则表达式

sed -i.bak 2d; 4d seq.log //-i.bak表示备份seq.log文件,备份后为seq/log/bak,并将源文件seq.log中的第2、4行删除;
sed -i.bak /^#/d /etc/fstab //删除注释行并备份文件,也可以直接-i,则不备份直接在原文件中 修改
sed -n /^[^#]/p/etc/fstab //只显示非注释行,不包含空行
sed -n /^#/!p/etc/fstab //只显示非注释行,包含空行,!表示模式匹配中的行做取反操作
sed -n /^$/= /etc/passwd//显示空行行号
sed 2p /etc/passwd//显示passwd全部内容
sed /root/a\\superman /etc/passwd //匹配的root行后添加superman
sed /root/i\\superman /etc/passwd //匹配的root行前添加superman
sed /root/c\\superman /etc/passwd //匹配的root行整行替换成superman
nl /etc/passwd | sed 2a\\tea //在第2行行后添加tea,也可以写成2a tea
sed -n s/root/& superman/p /etc/passwd //在root添加superman
sed -n s/rppt/superman& /p /etc/passwd //在root前添加superman

sed -n s/root/& er/gp /etc/fstab //表示查找替换root内容为rooter,这里的替换只是显示的时候,而不是修改了源文件;
//g表示行内有的全部替换,p表示显示替换成功的行;& 表示替换内容为rooter。

获取分区利用率
df | sed -En /^\\/dev\\/sd/s@.* ([0-9]+)% .*@\\1@p
//其中/^\\/dev\\/sd/是匹配/dev/sda,中间的\\是转义字符;
//后面的s@.* ([0-9]+)% .*@\\1@p是查找替换命令,只不过这里为了区分/,把/换成了@来表示;
//.*表示匹配任意长度任意字符,后面是([0-9]+%)分组,后面有个空格紧跟.*,df查出来的信息直接都有一定得空格间隔;
//@\\1表示引用([0-9]+%)中的内容,并且将查找的.* ([0-9]+)% .*信息全用这个表示;
//@p表示将模式空间中的内容追加到标准输出;
[root@centos8 ~]# df | sed -nr /^\\/dev\\/sd/s@ .* ([0-9]+%).*@ \\1@p
/dev/sda1 6%
/dev/sda2 1%
/dev/sda5 21%
[root@centos8 ~]# df | sed -nr /^\\/dev\\/sd/s@ .* ([0-9]+%).*@\\1@p
/dev/sda16%
/dev/sda21%
/dev/sda521%
[root@centos8 ~]# df | sed -nr /^\\/dev\\/sd/s@.* ([0-9]+%).*@\\1@p
6%
1%
21%
//以上是调节命令中的空格显示不同的信息。
df | sed -rn /^\\/dev\\/sd/ s#([^[:space:]]+[[:space:]]+)4(.*)%.*#\\2#p //也是看分区使用率,但是我没有看懂命令
df | sed -rn /^\\/dev\\/sd/ s#(\\S+\\s+)4(.*)%.*#\\2#p //同上,我也没看懂命令

ifconfig ens33 | sed -nr 2s/[^0-9]+([0-9.]+).*/\\1/p //获取IP地址、
//2表示从第二行开始、[^0-9]+表示非数字的字符出现至少1次及以上;
//([0-9.]+).*表示ip地址以及后面跟的其他内容;
//\\1表示将匹配的内容均替换为IP地址并显示;
ifconfig ens33 | sed -nr 2s/.* netmask ([0-9.]+) .*/\\1/p //取子网掩码

取目录
echo "/etc/sysconfig/network-scripts/ifcfg-ens33"|sed -rn s@(^/.*/)([^/]+)/?@\\1@p
dirname /etc/sysconfig/network-scripts/ifcfg-ens33
//(^/.*/)([^/]+)/? 第一个括号分组是匹配前面的目录名,第二个括号分组是匹配后面的文件名
//最后的/?是表示匹配/,出现0次或1次,其实这里没有这个也行
//上述的命令也可改成(^/.*/)+([^/]+),中间加个+号表示匹配前面的至少1次,不过会显得多余;
//(^/.*/)这里面/.*/的.*包含了/这个字符,外边的/是/pattern/的格式;
//dirname也是可以取目录名的;

取文件名(基名,基名是最后一个子目录或文件名)
echo "/etc/sysconfig/network-scripts/ifcfg-ens33"|sed -rn s@(^/.*/)([^/]+)/?@\\2@p
basename /etc/sysconfig/network-scripts/ifcfg-ens33
//命令和取目录名相同,只是引用的是\\2;
//basename是取基名;

取文件的前缀和后缀
echo test.txt.bak | sed -En s#(.*)\\.([^.]+)$#\\1#p //取文件的前缀
echo test.txt.bak | sed

    推荐阅读