linux - 文件处理三剑客awk sed grep

140 阅读5分钟

携手创作,共同成长!这是我参与「掘金日新计划 · 8 月更文挑战」的第9天,点击查看活动详

sed - 流式编辑器

sed原理

语法规则:sed 选项 '处理规则' 文件路径 

image-20220714094907337.png

sed与vim的区别

  • sed可以把处理文件的规则事先写好,就可以使用同一套规则处理多个文件,vim只能一个一个的进行编辑
  • sed处理文件一次处理一行,即同一时间内存中只有文件的一行,比较适合处理大型文件。

sed命令使用

语法规则:sed 选项 '处理规则' 文件路径

  • 处理规则 = 定位+命令
# 定位
1. 没有定位表示所有行
2. 行号定位
	n 表示定位到第n行
	n,m 表示从第n行到第m行
	n;m;...  表示第n行和第m行,指定行以分号进行分隔
3. 正则定位
	/正则表达式/  匹配到正则表达式的行

# 命令
d 删除
p 将每一行内容输出到屏幕
s/正则表达式/新内容/gi  将正则表达式匹配到的内容替换成新内容,{g表示匹配所有,i表示忽略大小写,gi可以不写}
  • 选项
-n 取消sed命令的默认输出到屏幕
-i 规则对源文件生效不输出到屏幕,只要不加-i规则就不会对源文件生效只是临时修改
  • sed可以和|配合使用
ifconfig eth0 | sed 's/eth0/ens33/'
head -3 a.txt | sed 's/zhy/ZHY/gi'
  • 案例
sed 'p' a.txt
- 结果是每一行都输出两次,第一次输出是命令'p'的规则处理结果,第二次是sed默认输出至屏幕

sed -n 'p' a.txt
- 结果是每一行只有一次输出,和源文件一致,输出的是命令'p'的处理结果,sed默认输出被-n选项取消

sed 'd' a.txt
- 结果是屏幕什么都不会输出。文件从硬盘一行一行读入内存,sed的'd'命令对内存中的每一行数据进行删除操作,由于将内存中的数据删除,规则处理后内存中没有数据,因此规则处理不会向屏幕输出同时由于内存中没有数据了,sed命令也无法读取数据向屏幕输出。

sed '1p' a.txt
- 结果是第一行输出两次,其余行只输出一次,通过定位'1'定位到第一行,第一行执行'p'命令,从第二行开始就不符合定位的规则,因此不再执行'p'命令

sed '1,3d' a.txt
- 第一行和第三行数据不输出

sed '/zhy/p' a.txt
- 结果是只有包含zhy的一行数据会被输出两次,因为定位到了包含zhy的行之后还要执行'p'命令,而没有包含zhy的行不会执行'p'命令

sed 's/zhy/ZHY/gi' a.txt
- 结果是在屏幕上输出zhy全部被ZHY替换的结果,sed默认将规则处理之后的结果输出到屏幕上

awk

awk原理

原理和sed差不多,也是一行一行的进行处理,但是没有-i向文件中写入的选项,并且没有默认输出至屏幕。

awk擅长处理有规则的文本,主要用于做一些格式处理

awk使用

awk 选项 '处理规则' 文件路径

  • 选项
-F
指定分隔符,不指定默认就是以空格(不管多少个空格都按一个为准)为分隔符,将每一行数据以分隔符分成几段
-F:  以:为分隔符
-F  以空格为分隔符
  • 处理规则=定位+命令
# 命令
{print $n}  输出一行的第n段,当n=0时输出一整行
{print $n, $m}  输出一行的第n段和第m段

# 定位
1. 行号定位
	NR == n 定位到第n行
	NR >= n && NR <= m  定位到n~m行
	NR == n && NR == m  定位到n行和m行
2. 正则定位
	/正则表达式/  匹配到正则表达式的行
	$n ~ /正则表达式/ 只用一行的某一段进行正则表达式的匹配
  • awk和|结合使用
ifconfig eth0 | awk 'NR == 2{print $2}' | awk -F. '{print$2}'                
  • NF
NF是每一行被分成的段数,$NF表示每一行的最后一段
  • 案例:以/etc/passwd前四行数据为例
awk -F: '{print$0}' b.txt
- 结果是查看b.txt 和cat b.txt效果一致。以:为分隔符,打印一整行数据

awk -F: '{print$1,$NF}' b.txt
- 以:为分隔符,打印每行的第一段和最后一段

awk -F: 'NR==1{print$1,$NF}' b.txt
- 以:为分隔符,打印第一行的第一段和最后一段

awk -F: 'NR>=2 && NR<=4 {print$1,$NF}' b.txt
- 以:为分隔符,打印2-4行的第一段和最后一段

awk -F: '/m/ {print$1,$NF}' b.txt
- 以:为分隔符,打印匹配到正则表达式的所有行的第一段和最后一段

awk -F: '$6~/m/ {print$1,$NF}' b.txt 
- 以:为分隔符,只用一行的第6段和/m/进行匹配

grep - 过滤

grep擅长过滤,将符合过滤规则的内容过滤出来

grep使用

grep 选项 '过滤规则(正则表达式)' 文件,需要注意的是grep命令没有定位功能,是在全部结果中进行过滤。

# -n 显示过滤内容所在的行号
grep -n 'root' /etc/passwd
- 在/etc/passwd文件中过滤包含有root的行,并且显示行号

# -i 忽略大小写
grep -in 'root' /etc/passwd

# -l 判断文件中是否包含过滤规则匹配的内容,如果包含则输出文件名称
grep -l 'root' /etc/passwd  # 结果 /etc/passwd

# -r 递归,和-l同时使用,可以扫描目录下的所有文件判断它们是否包含过滤规则匹配的内容,如果包含返回文件名称
grep -rl 'root' /etc/

# grep和管道符结合使用 - grep可以在管道符中获取数据
ps aux | grep python
- ps aux查看当前系统中所有进程,使用grep过滤出和Python相关的进程,默认会将和grep的这条记录也显示出来
[root@VM-4-2-centos ~]# ps aux | grep ssh
root        2777  0.0  0.1  85540  4972 ?        Ss   Mar23   0:41 /usr/sbin/sshd -D
root     2373176  0.0  0.2 163772 10408 ?        Ss   09:28   0:00 sshd: root [priv]
root     2373188  0.0  0.1 156992  5724 ?        S    09:28   0:00 sshd: root@pts/0
root     2374910  0.0  0.0  12136  1192 pts/0    S+   09:40   0:00 grep --color=auto ssh

如果不想要和grep相关的这条进程可以使用一下两种方式进行处理:
1. ps aux | grep ssh | grep -v grep  
- grep -v 表示将规则内容过滤掉

2. ps aux |grep [s]sh
- 将需要过滤的进程的第一个字母放在[]中