grep命令
grep全面搜索正则表达式并把行打印出来,是一种强大的文本搜索工具,它能使用正则表达式搜索文本,并把匹配的行打印出来。它的输出一般是打印在屏幕上。
Unix的grep家族包括grep、egrep和fgrep。egrep和fgrep的命令只跟grep有很小不同。egrep是grep的扩展,支持更多的re元字符, fgrep就是fixed grep或fast grep,它们把所有的字母都看作单词,也就是说,正则表达式中的元字符表示回其自身的字面意义,不再特殊。linux使用GNU版本的grep。它功能更强,可以通过-G、-E、-F命令行选项来使用egrep和fgrep的功能。
grep如何工作的?
grep 命令在一个或多个文件中查找某个字符模式。如果这个模式中包含空格,就必须用引号把它括起来。 grep 命令中,模式可以是一个被引号括括起来的字符串,也可以是单个词,位于模式之后所有的单词都被视为文件名。 grep 将输出发送到屏幕,它不会对输入文件进行任何修改或变化。
示例1:grep root /etc/passwd
说明:grep命令将在文件/etc/passwd中查找模式root。如果查找成功,文件中相应的行就会显示在屏幕上,返回状态为0。如果查找失败,就不会有任何输出,返回状态为1。如果文件不存在,屏幕会显示报错信息,返回状态为2。
$ grep root /etc/passwd123 # 文件不存在
grep: /etc/passwd123: 没有那个文件或目录
$ echo $?
2 # 状态值为2
$ grep lala /etc/passwd # 查找模式不匹配
$ echo $?
1 # 状态值为1
$ grep root /etc/passwd # 成功匹配
root:x:0:0:root:/root:/bin/bash
operator:x:11:0:operator:/root:/sbin/nologin
$ echo $?
0 # 状态值为0,成功匹配
grep命令的输入可以来自文件,也可以来自标准输入或者管道。
示例2:ps aux | grep docker
[root@moli-04 ~]# ps aux | grep docker
root 893 0.1 5.5 486428 55472 ? Ssl 11:33 0:02 /usr/bin/dockerd
root 986 0.0 2.9 384508 29544 ? Ssl 11:33 0:01 docker-containerd --config /var/run/docker/containerd/containerd.toml
root 1296 0.0 0.2 108964 2628 ? Sl 11:33 0:00 /usr/bin/docker-proxy -proto tcp -host-ip 0.0.0.0 -host-port 5000 -container-ip 172.17.0.2 -container-port 5000
root 1301 0.0 0.2 7488 2676 ? Sl 11:33 0:00 docker-containerd-shim -namespace moby -workdir /var/lib/docker/containerd/daemon/io.containerd.runtime.v1.linux/moby/63683775af1b8dd27080dbf898619a3f50a17bf557ac0e133ab52310c84dbf5e -address /var/run/docker/containerd/docker-containerd.sock -containerd-binary /usr/bin/docker-containerd -runtime-root /var/run/docker/runtime-runc
root 1317 0.0 0.8 20272 8128 ? Ssl 11:33 0:00 registry serve /etc/docker/registry/config.yml
root 1404 0.0 0.0 112720 968 pts/0 R+ 12:00 0:00 grep --color=auto docker
ps aux
命令的输入被送到grep,然后包含docker
的行都被输出到屏幕上。
正则表达式
grep支持很多正则表达式元字符,以便用户更精确地定义查找模式。
下面列出grep支持的常用基本表达式:
字符 | 含义 |
---|---|
a | 匹配字母a |
. | 匹配任意一个字符 |
* | 匹配前一个字符出现0次或多次 |
.* | 匹配任意字符 |
[ ] | 匹配集合中任意一个字符,括号中为一个集合 |
[x-y] | 匹配连续的字符串范围 |
^ | 匹配字符的开头 |
$ | 匹配字符的结尾 |
[^] | 匹配否点,对括号中的集合取反 |
\ | 匹配转义后的字符串 |
\{n,m\} | 匹配前一个字符出现n到m次 |
\{n,\} | 匹配前一个字符至少出现n次 |
\{n\} | 匹配前一个字符出现n次 |
() | 保存已匹配的字符串,最大存储9个,括号左右需要使用转义字符(这里不知道为什么显示不了...) |
grep命令的常用选项
选项 | 说明 |
---|---|
-A num | (A即after)显示匹配的行,并显示匹配行的后num行,num为数字 |
-B num | (B即before)除了显示匹配的行,还显示匹配行的前num行,num为数字 |
-C num | 前后匹配(相当于-A和-B)除了显示匹配的行,还显示匹配行的前后num行 |
-n | 在输出结果显示行号,行号是该行在原来文件里的行号,而不是输出结果的行号 |
-v | 取反,输出与匹配模式相反的内容 |
-E | 相当与egrep,后面的模式是扩展正则表达式(grep -E == egrep) |
-o | 只显示匹配内容,grep默认输出匹配内容的行,加上-o选项只输出匹配的模式 |
-d | 当指定要查找的是目录而非文件时,必须使用这项参数,否则grep指令将回报信息并停止动作。 |
-c | count统计,统计匹配结果的行数,有n行匹配就输出数字n |
实例:
将/etc/passwd的前10行输出保存到/tmp/grep.txt,下面grep实例都用这个文本文件。
[root@moli-04 ~]$ head -n 10 /etc/passwd > /tmp/grep.txt
[root@moli-04 ~]$ cat /!$
cat //tmp/grep.txt
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:查找特定字符串,显示行号
[root@moli-04 ~]$ grep -n "root" /tmp/grep.txt
1:root:x:0:0:root:/root:/bin/bash
10:operator:x:11:0:operator:/root:/sbin/nologin
示例2:取反,将不包含root的行输出,并显示行号
[root@moli-04 ~]$ grep -nv "root" /tmp/grep.txt
2:bin:x:1:1:bin:/bin:/sbin/nologin
3:daemon:x:2:2:daemon:/sbin:/sbin/nologin
4:adm:x:3:4:adm:/var/adm:/sbin/nologin
5:lp:x:4:7:lp:/var/spool/lpd:/sbin/nologin
6:sync:x:5:0:sync:/sbin:/bin/sync
7:shutdown:x:6:0:shutdown:/sbin:/sbin/shutdown
8:halt:x:7:0:halt:/sbin:/sbin/halt
9:mail:x:8:12:mail:/var/spool/mail:/sbin/nologin
示例3:-A,-B,-C的使用
[root@moli-04 ~]$ grep -A 1 root /tmp/grep.txt
root:x:0:0:root:/root:/bin/bash
bin:x:1:1:bin:/bin:/sbin/nologin
--
operator:x:11:0:operator:/root:/sbin/nologin
[root@moli-04 ~]$ grep -B 1 root /tmp/grep.txt
root:x:0:0:root:/root:/bin/bash
--
mail:x:8:12:mail:/var/spool/mail:/sbin/nologin
operator:x:11:0:operator:/root:/sbin/nologin
[root@moli-04 ~]$ grep -C 1 root /tmp/grep.txt
root:x:0:0:root:/root:/bin/bash
bin:x:1:1:bin:/bin:/sbin/nologin
--
mail:x:8:12:mail:/var/spool/mail:/sbin/nologin
operator:x:11:0:operator:/root:/sbin/nologin
第一条命令输出包含root的行,并输出它的后一行。
第二条命令输出包含root的行,并输出它的前一行。
第三条命令输出包含rott的行,并输出它的前后一行。
示例4:-c统计行数,包含root的行有几行
[root@moli-04 ~]$ grep -c root /tmp/grep.txt
2
示例5:^,$的使用
# 匹配以r字母为开头的行
[root@moli-04 ~]$ grep ^r /tmp/grep.txt
root:x:0:0:root:/root:/bin/bash
[root@moli-04 ~]#
# 匹配以nologin单词为结尾的行
[root@moli-04 ~]$ grep nologin$ /tmp/grep.txt
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
mail:x:8:12:mail:/var/spool/mail:/sbin/nologin
operator:x:11:0:operator:/root:/sbin/nologin
示例6:[]的使用
# 查找包含ost或者oot的行
[root@moli-04 ~]$ grep o[os]t /tmp/grep.txt
root:x:0:0:root:/root:/bin/bash
operator:x:11:0:operator:/root:/sbin/nologin
示例7:匹配包含数字和包含小写字母的行'[0-9]'和'[a-z]'
$ grep '[0-9]' /tmp/grep.txt
$ grep '[a-z]' /tmp/grep.txt
输出结果太长就不复制进来了,多多动手实践吧(=゚ω゚)。
示例8:正则表达式实践
test.txt文件内容如下,注意有空白行。
aaa
bbb
111
222
AAA
BBB
hell world
I love python
pppppython
匹配数字开头的行:
$ grep '^[0-9]' test.txt
111
222
匹配小写字母开头的行:
$ grep '^[a-z]' test.txt
aaa
bbb
hell world
pppppython
匹配空白行,这里-n显示行号显示空白行在第几行
$ grep -n '^$' test.txt
7:
逻辑匹配或者‘|’,需要使用转义字符''
$ grep '111\|222' test.txt # 匹配111或者222
111
222
并且,利用管道
$ grep 'love' test.txt | grep 'python' # 匹配带有love和python的行
I love python
匹配p字母出现至少4次
$ grep 'p\{4,\}' test.txt # 中括号左右需要使用转义字符\
pppppython
egrep扩展正则表达式
egrep 在 grep 的基础上增加了更多的元字符。但是 egrep 不允许使用(),\{\}.下面是egrep支持使用的正则表达式元字符(只列举新增的)。
字符 | 说明 |
---|---|
+ | 匹配一个或多个前面的字符,至少一个 |
? | 匹配0个或1个起那么的字符,只能0或者1 |
竖线 | 或者(这里竖线就用中文了,因为markdown表格的竖线转义不了...) |
() | 匹配正则集合 |
sed命令
- sed 是一种新型的,非交互式的编辑器。它能执行与编辑器 vi 和 ex 相同的编辑任务。
- sed 编辑器没有提供交互式使用方式,使用者只能在命令行输入编辑命令、指定文件名,然后在屏幕上查看输出。
- sed 编辑器没有破坏性,它不会修改文件,除非使用 shell 重定向来保存输出结果。
- 默认情况下,所有的输出行都被打印到屏幕上。
sed工作流程
sed通过文件或者管道读取文件内容,但sed默认并不直接修改源文件,而是将读入的内容复制到缓冲区中,我们称之为模式空间,所有的指令操作都是在模式空间中进行的,然后sed根据对应的指令对模式空间内的内容进行处理并输出结果,默认输出至标准输出(屏幕)。
sed基本语法
用法: sed [选项] {脚本指令} [输入文件]
sed操作地址匹配
sed 命令在没有给定的位置时,默认会处理所有行;
sed支持下面几种地址类型;
示例 | 说明 |
---|---|
number | 指定输入文件的唯一行号 |
first~step | 指定first开始,并指定操作步长为step。比如1~2,指定第一行、第三行、第五行...为操作地址。 |
$ | 匹配文件最后一行 |
/regexp/ | 通过正则表达式匹配操作地址,//中间是正则表达式 |
addr1.addr2 | 匹配从操作地址1到操作地址2的所有行 |
addr1,+N | 匹配地址1以及后面的N行内容 |
sed常用选项
选项 | 说明 |
---|---|
-n | 静默输出,sed程序默认在所有脚本指令执行完毕后自动打印模式空间中的内容,该选项可以屏蔽自动打印 |
-e | 允许多个脚本指令被执行,指令顺序会影响结果 |
-i | 修改源文件的内容,慎用 |
-f | 从文件中读取脚本指令,对编写自动脚本程序很实用 |
-r | 让sef支持扩展正则表示式 |
sed常用指令
指令 | 说明 |
---|---|
a | 追加(在原先行后追加) |
d | 删除 |
c | 更改 |
i | 插入(在原先行前插入) |
s | 替换 |
l | 打印(显示非打印字符) |
L | 打印(不显示非打印字符) |
p | 打印 |
w | 保存至文件 |
部分指令详解
替换指令:s
使用格式:[address]s/pattern/replacement/flags
address是操作地址,s为替换指令,pattern需要替换的内容,replacement替换的新内容,flags标记。
flags有几种:
- n 表示1-512之间的数字,对模式空间中指定模式的第n次出现进行替换,如有2个hello,替换第二个hello为world可以这样写
s/hello/world/2
- g 表示全局替换。比如把模式空间中所有的a替换成b,可以这样写
s/a/b/g
- p 打印模式空间的内容.默认情况下, sed 把输入行打印在屏幕上,选项-n 用于取消默认打印操纵。选项-n 和命令 p 同时出现时, sed 可打印选定的内容。
- w file 将模式空间的内容写到文件file中
sed示例
sed.txt文件内容
$ cat sed.txt
ONBOOT=yes
IPADDR=192.168.30.6
NETMASK=255.255.255.0
GATEWAY=192.168.30.2
DNS=119.29.29.29
在第一行后面追加TYPE=Ethernet
$ sed '1a TYPE=Ethernet' sed.txt
ONBOOT=yes
TYPE=Ethernet #追加项
IPADDR=192.168.30.6
NETMASK=255.255.255.0
GATEWAY=192.168.30.2
DNS=119.29.29.29
在第2行前面插入TYPE=Ethernet
$ sed '2i TYPE=Ethernet' sed.txt
ONBOOT=yes
TYPE=Ethernet # 插入项
IPADDR=192.168.30.6
NETMASK=255.255.255.0
GATEWAY=192.168.30.2
DNS=119.29.29.29
全局替换yes为no
$ sed 's/yes/no/g' sed.txt
ONBOOT=no # yes被替换为no
IPADDR=192.168.30.6
NETMASK=255.255.255.0
GATEWAY=192.168.30.2
DNS=119.29.29.29
删除第1,2行的内容
$ sed '1,2d' sed.txt
# 1,2行没了
NETMASK=255.255.255.0
GATEWAY=192.168.30.2
DNS=119.29.29.29
匹配以DNS为开头的行,并在该行前插入DEVICE=ens33
$ sed '/^DNS/i DEVICE=ens33' sed.txt
ONBOOT=yes
IPADDR=192.168.30.6
NETMASK=255.255.255.0
GATEWAY=192.168.30.2
DEVICE=ens33 # 插入的行,下一行是以DNS为开头
DNS=119.29.29.29
除了直接将操作指令写在命令行里,还可以将操作指令写在脚本里,然后使用sed -f
读取指令。
创建脚本,内容如下
$ cat sed.sh
# 这个脚本的作用是打印文件的奇数行,需要配合-n选项使用
1~2p
-f读取指令
$ sed -f sed.sh -n sed.txt
ONBOOT=yes
NETMASK=255.255.255.0
DNS=119.29.29.29
当需要执行多个指令的时候,可以有几种方式。
$ sed -n 's/yes/no/;s/static/dhcp/p' sed.txt #使用分号
$ sed -e 's/yes/no/' -e 's/static/dhcp/' sed.txt # 使用-e选项
$ sed '
>s/yes/no/
>s/static/dhcp/' sed.txt
常见案例1:使用sed命令将文件带#的行删除
实际在修改配置文件的时候,配置文件带有大量的注释,通常以'#'为开头,于是可以将这些以#为开头的行删掉。
[root@moli-04 tmp]$ cat sed2.txt
#ajksshdja
jskdjks
#kjklasj
123
$ sed -i '/^#/d' sed2.txt
[root@moli-04 tmp]$ cat sed2.txt
jskdjks
123
常见案例2:删除空白行与删除以数字开头的行
$ sed '/^$/d' sed.txt
$ sed '/^[0-9]*/d' sed.txt
常见案例3:查找网卡对应ip地址
$ ifconfig | grep -A1 ens33|grep inet|sed s/^.*inet//g | sed 's/netmask.*$//g'
192.168.30.6