grep

grep命令将根据用户指定的模式(pattern)对目标进行过滤,显示被模式匹配到的行。

两种使用形式:

grep [option] pattern [file1,fli2,...]

some command | grep [option] pattern

option 含义
-i 忽略大小写
-c 只输出匹配行的数量
-n 显示行号
-r 递归搜索
-E 支持扩展正则表达式
-w 匹配整个单词
-l 只列出匹配的文件名
-F 不支持正则,按字符串字面意思进行匹配
-C 匹配行及其上下文,如-C2,匹配行的上下两行
-A 匹配行的下文
-B 匹配行的上文

显示/etc/passwd中带root的行

1
2
3
[root@VM-0-2-centos ~] grep root /etc/passwd
root:x:0:0:root:/root:/bin/bash
operator:x:11:0:operator:/root:/sbin/nologin

显示/etc/passwd中带root的行及行号

1
2
3
[root@VM-0-2-centos ~] grep -n root /etc/passwd
1:root:x:0:0:root:/root:/bin/bash
10:operator:x:11:0:operator:/root:/sbin/nologin

显示匹配行的数量

1
2
[root@VM-0-2-centos ~] grep -c root /etc/passwd
2

对一个目录进行递归搜索查找匹配行

1
2
3
4
5
[root@VM-0-2-centos /] grep -r root /notebooks/
/notebooks/shell基础.md: [root@VM-0-2-centos ~] a=10
/notebooks/shell基础.md: [root@VM-0-2-centos ~] b=20
/notebooks/shell基础.md: [root@VM-0-2-centos ~] echo $((a+b)) # 变量可以不加$
/notebooks/shell基础.md: [root@VM-0-2-centos ~] echo $(($a+$b))

查询以r开头的行

1
2
3
[root@VM-0-2-centos ~] grep -n ^r /etc/passwd  
1:root:x:0:0:root:/root:/bin/bash
18:rpc:x:32:32:Rpcbind Daemon:/var/lib/rpcbind:/sbin/nologin

查询以sh结尾的行

1
2
[root@VM-0-2-centos ~] grep -n sh$ /etc/passwd  
1:root:x:0:0:root:/root:/bin/bash

查询字母o连续出现两次的所在行

1
2
3
4
5
6
[root@VM-0-2-centos ~] grep -En 'o{2}' /etc/passwd  
1:root:x:0:0:root:/root:/bin/bash
5:lp:x:4:7:lp:/var/spool/lpd:/sbin/nologin
9:mail:x:8:12:mail:/var/spool/mail:/sbin/nologin
10:operator:x:11:0:operator:/root:/sbin/nologin
22:postfix:x:89:89::/var/spool/postfix:/sbin/nologin

注:grep默认只支持基础正则,当需要扩展正则时,需要加-E或者使用egrep

基础正则

符号 含义
^ 以…开头,如^a
$ 以…结尾,如a$
^$ 空行,什么符号都没有
. 表示任意一个字符
\ 转义字符,\n相当于回车,\t相当于tab键
* 表示前一个字符连续出现了0次或0次以上
.* 表示任意字符,包括空行
[] 匹配字符范围,如[1,5],只匹配包含数字1-5
[^] [^abc]表示排除a,b,c

扩展正则

符号 含义
+ 表示前一个字符连续出现1次或1次以上
|
() 表示一个整体
{} {n,m}前一个字符至少连续出现n次,最多连续出现mci

显示匹配包含Daemon的行及其上下两行

1
2
3
4
5
6
[root@VM-0-2-centos ~] grep -C2 Daemon /etc/passwd  
polkitd:x:999:998:User for polkitd:/:/sbin/nologin
libstoragemgmt:x:998:997:daemon account for libstoragemgmt:/var/run/lsm:/sbin/nologin
rpc:x:32:32:Rpcbind Daemon:/var/lib/rpcbind:/sbin/nologin
ntp:x:38:38::/etc/ntp:/sbin/nologin
abrt:x:173:173::/etc/abrt:/sbin/nologin

sed

sed是流编辑器,一次处理一行,将每行放在模式空间中进行处理,处理完成后清除掉这个空间,也就是说sed操作文件并不会改变源文件。

两种使用形式:

sed [option] "pattern command" file

some command | sed [option] "pattern command"

option 含义
-n 只打印模式匹配的行
-f 加载存放动作的文件
-r 支持扩展正则
-i 直接修改文件
匹配模式(pattern) 含义
5 只处理第5行
5,10 只处理第5到第10行
/pattern/ 只处理能匹配pattern的行
/pattern1/,/pattern2/ 只处理从匹配pattern1到pattern2之间的行
命令(command) 含义
a 在匹配行后新增
c 取代
d 删除
i 在匹配行前新增
r 外部文件读入新增到行后
w 匹配行写入到外部文件
p 打印
s 修改

s /old/new/ 只修改匹配行中第一个old
s /old/new/g 修改匹配行中所有的old

查询

sedgrep一样,默认只支持普通正则,要用扩展正则需要加-r

打印连续出现两次字母o的行

1
2
3
4
5
6
[root@VM-0-2-centos ~] sed -rn '/o{2}/ p' /etc/passwd
root:x:0:0:root:/root:/bin/bash
lp:x:4:7:lp:/var/spool/lpd:/sbin/nologin
mail:x:8:12:mail:/var/spool/mail:/sbin/nologin
operator:x:11:0:operator:/root:/sbin/nologin
postfix:x:89:89::/var/spool/postfix:/sbin/nologin

打印以rpc开头和post 开头的之间的行

1
2
3
4
5
6
[root@VM-0-2-centos ~] sed -n '/^rpc/,/^post/ p' /etc/passwd
rpc:x:32:32:Rpcbind Daemon:/var/lib/rpcbind:/sbin/nologin
ntp:x:38:38::/etc/ntp:/sbin/nologin
abrt:x:173:173::/etc/abrt:/sbin/nologin
sshd:x:74:74:Privilege-separated SSH:/var/empty/sshd:/sbin/nologin
postfix:x:89:89::/var/spool/postfix:/sbin/nologin

新增

在匹配行后新增

1
2
3
4
5
$ sed '/^他/ a 敢笑黄巢不丈夫' test.txt 
宝骏踏断命里刺
胭脂洒满暮光谷
他日若随凌云志
敢笑黄巢不丈夫

在匹配行前新增

1
2
3
4
5
$ sed '/^宝  i 兰花草  test.txt 
兰花草
宝骏踏断命里刺
胭脂洒满暮光谷
他日若随凌云志

从外部文件插入内容

content.txt

1
2
3
4
5
6
7
我从山中来
带着兰花草
家中无富贵
口袋无财宝
寒风终刺骨
勤为好仕途
博得明月出
1
2
3
4
5
6
7
8
9
10
11
$ sed '3 r content.txt' test.txt
宝骏踏断命里刺
胭脂洒满暮光谷
他日若随凌云志
我从山中来
带着兰花草
家中无富贵
口袋无财宝
寒风终刺骨
勤为好仕途
博得明月出

注意:上述对文件的插入新增操作,都不会修改源文件,如果要直接修改源文件,需要加-i

修改

test.txt

1
2
3
yellow blue yellow
read green grey
yellow

只修改匹配到的第一个

1
2
3
4
$ sed 's/yellow/white/' test.txt 
white blue yellow
read green grey
white

修改所有匹配到的内容

1
2
3
4
$ sed 's/yellow/white/g' test.txt 
white blue white
read green grey
white

这里s/old/new/可以用其它任意分隔符,如s#old#new#。

注:同样地,修改不会影响源文件,要直接修改加-i

awk

awk命令会把文件逐行的读入,以空格为默认分隔符将每行切片,切开的部分再进行后续处理并生成结果报告。

之所以叫 AWK 是因为其取了三位创始人 Alfred Aho,Peter Weinberger, 和 Brian Kernighan 的 Family Name 的首字符。

两种使用形式:

awk 'BEGIN{} pattern {commands} END{}' file

some command | awk 'BEGIN{} pattern {commands} END{}'

选项 含义
BEGIN{} 处理数据之前执行,只执行一次
pattern 匹配模式
{commands} 处理的命令
END{} 处理数据之后执行,只执行一次
内置变量 含义
$0 整行内容
$1-$n 当前行的第1-n个字段
NF(Number Field) 当前行字段数
NR(Number Row) 当前行行号,从1开始
FS(Field Separator) 输入字段分隔符,默认为空格或tab键
RS(Row Separator) 输入行分隔符,默认为回车符
OFS(Output Field Separator) 输出字段分隔符,默认为空格
ORS(Output Row Separator) 输出行分隔符,默认为回车符

打印文件所有内容

1
2
3
4
5
$ awk '{print $0}' test.txt 
id name age
001 bob 19
002 tim 20
003 jay 17

打印id列内容

1
2
3
4
5
$ awk '{print $1}' test.txt 
id
001
002
003

awk的处理流程:把文件内容做逐行处理,每一行内容作为输入,并赋值给$0,将行按照分隔符切割(默认空格),从$1开始,然后对行进行匹配,执行动作,最后打印输出内容。

打印/etc/passwd第一列内容`

/etc/passwd

1
2
3
4
5
6
7
8
9
10
11
$ cat /etc/passwd
root:x:0:0:root:/root:/bin/bash
bin:x:1:1:bin:/bin:/sbin/nologin
daemon:x:2:2:daemon:/sbin:/sbin/nologin
adm:x:3:4:adm:/var/adm:/sbin/nologin
lp:x:4:7:lp:/var/spool/lpd:/sbin/nologin
sync:x:5:0:sync:/sbin:/bin/sync
shutdown:x:6:0:shutdown:/sbin:/sbin/shutdown
halt:x:7:0:halt:/sbin:/sbin/halt
mail:x:8:12:mail:/var/spool/mail:/sbin/nologin
operator:x:11:0:operator:/root:/sbin/nologin
1
2
3
4
5
6
7
8
9
10
11
12
# 通过BEGIN作为前置条件指定分割符为":"
$ awk 'BEGIN{FS=":"} {print $1}' /etc/passwd
root
bin
daemon
adm
lp
sync
shutdown
halt
mail
operator

也可以这样分割

1
2
3
4
5
6
7
8
9
10
11
$ awk -F":" '{print $1}' /etc/passwd
root
bin
daemon
adm
lp
sync
shutdown
halt
mail
operator

打印/etc/passwd第2-7行的第一列和最后一列内容

1
2
3
4
5
6
7
8
# &&:与,||:或,NF:当前行的字段数,$NF即最后一列
$ awk -F":" 'NR>=2 && NR<=7 {print $1,$NF}' /etc/passwd
bin /sbin/nologin
daemon /sbin/nologin
adm /sbin/nologin
lp /sbin/nologin
sync /bin/sync
shutdown /sbin/shutdown

打印/etc/passwd第2-7行的第一列和最后一列内容,并将输出内容以|分隔

1
2
3
4
5
6
7
8
# 如上例所示,输出内容默认以空格分隔,要想指定输出内容的列之间的分隔符,可以用OFS指定
$ awk -F":" 'BEGIN{OFS="|"} NR>=2 && NR<=7 {print $1,$NF}' /etc/passwd
bin|/sbin/nologin
daemon|/sbin/nologin
adm|/sbin/nologin
lp|/sbin/nologin
sync|/bin/sync
shutdown|/sbin/shutdown

指定换行符

1
2
3
4
5
6
7
# awk默认以回车符为换行符,通过RS指定以","为换行符
$ echo "Benz,Audi,BMW,Porsche,Ferrari" | awk 'BEGIN{RS=","} {print $0}'
Benz
Audi
BMW
Porsche
Ferrari

awk还支持循环、条件判断等语法

如果行号等于5,打印该行内容

1
2
$ awk -F":" '{if(NR==5) print $0}' /etc/passwd
lp:x:4:7:lp:/var/spool/lpd:/sbin/nologin

该语句,等价于:

1
2
$ awk -F":" 'NR==5 {print $0}' /etc/passwd
lp:x:4:7:lp:/var/spool/lpd:/sbin/nologin

awk支持printf格式化输出

格式符 含义
%s 字符串
%d 十进制数字
%f 浮点数

总结

grepsedawk三剑客都是文本处理的好手,但各有侧重:

  • grep 更适合单纯的查找或匹配文本
  • sed 更适合编辑匹配到的文本
  • awk 更适合格式化文本,对文本进行较复杂格式处理