Linux运维:grep与sed命令

syushin

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 







阅读 3.8k
913 声望
313 粉丝
0 条评论
你知道吗?

913 声望
313 粉丝
宣传栏