侧边栏壁纸
博主头像
张种恩的技术小栈博主等级

行动起来,活在当下

  • 累计撰写 748 篇文章
  • 累计创建 65 个标签
  • 累计收到 39 条评论

目 录CONTENT

文章目录

Linux基础(60)之sed入门及进阶

zze
zze
2019-12-19 / 0 评论 / 0 点赞 / 697 阅读 / 12207 字

不定期更新相关视频,抖音点击左上角加号后扫一扫右方侧边栏二维码关注我~正在更新《Shell其实很简单》系列

介绍

Linux sed 命令是利用脚本来处理文本文件,全称 ”Stream Editor“,是一种流编辑器,它也被称为行编辑器,因为它在实现文本处理时是逐行进行处理的。
sed 可依照脚本的指令来处理、编辑文本文件。
sed 主要用来自动编辑一个或多个文件、简化对文件的反复操作、编写转换程序等。

模式空间

sed 命令会从文件读取一行并将该行放入模式空间,然后在模式空间中看该行是否符合我们指定的条件,如果符合或者说是被匹配到了那么就对该行做相应处理。

保持空间

sed 命令的保持空间相当于仓库,在模式空间对数据进行处理时,可以把数据临时存储到保持空间;作为模式空间的一个辅助临时缓冲区,但又是相互独立,可以进行交互,命令可以寻址模式空间但是不能寻址保持空间。可以使用高级命令 hHgG 与模式空间进行交互。

基本使用

set [option]... [script] [input_file] ...
    option:
        -n:静默模式,不把处理后的结果输出到屏幕;
        -e:多点编辑;
        -f <file>:从文件中读取编辑脚本;
        -r:支持正则表达式;
        -i:在原文件中编辑,而不是输出到屏幕;
    script:sed 脚本;
    input_file:处理的文件,可以有多个,处理完第一个就会接着处理第二个;

sed 中也可以使用地址定界的方式来匹配文本,和 VIM 中底行模式相同,可参考【地址定界】。

d 删除

d 命令用来删除匹配到的内容。
例 1:删除 /etc/fstab 中以 UUID 开头的行。

$ sed '/^UUID/d' /etc/fstab

#
# /etc/fstab
# Created by anaconda on Tue Dec  3 20:47:57 2019
#
# Accessible filesystems, by reference, are maintained under '/dev/disk'
# See man pages fstab(5), findfs(8), mount(8) and/or blkid(8) for more info
#

例 2 :删除 /etc/fstab 中所有的空白行和以 # 开头的行。

$ sed '/^[$#]/d' /etc/fstab

UUID=f67055b0-03ba-4e15-a1e1-8124505d1d31 /                       xfs     defaults        0 0
UUID=76c059b7-1c58-429b-8936-ac34a749976d /boot                   xfs     defaults        0 0
UUID=2702f1d8-3154-4194-a25f-50c304d99e67 swap                    swap    defaults        0 0

例 3:把 /etc/fstab 中删除 1~3 行后的内容输出到屏幕。

$ sed '1,3d' /etc/fstab 
# Created by anaconda on Tue Dec  3 20:47:57 2019
#
# Accessible filesystems, by reference, are maintained under '/dev/disk'
# See man pages fstab(5), findfs(8), mount(8) and/or blkid(8) for more info
#
UUID=f67055b0-03ba-4e15-a1e1-8124505d1d31 /                       xfs     defaults        0 0
UUID=76c059b7-1c58-429b-8936-ac34a749976d /boot                   xfs     defaults        0 0
UUID=2702f1d8-3154-4194-a25f-50c304d99e67 swap                    swap    defaults        0 0

p 打印

p 命令用来显示模式空间的内容。
例 1:显示 /etc/fstab 中以 UUID 开头的行。

$ sed '/^UUID/p' fstab -n
UUID=f67055b0-03ba-4e15-a1e1-8124505d1d31 /                       xfs     defaults        0 0
UUID=76c059b7-1c58-429b-8936-ac34a749976d /boot                   xfs     defaults        0 0
UUID=2702f1d8-3154-4194-a25f-50c304d99e67 swap                    swap    defaults        0 0

因默认会显示处理结果文本,所以这里要使用 -n 选项开启静默模式,仅显示通过 p 命令输出的行。

a 追加文本

a \<text> 命令可以把给定的 text 文本追加到每一个符合条件的行后面。
例 1:给 /etc/fstab 中每一个以 UUID 开头的行后面加入 # hello sed 文本。

$ sed '/^UUID/a \# hello sed' /etc/fstab 

#
# /etc/fstab
# Created by anaconda on Tue Dec  3 20:47:57 2019
#
# Accessible filesystems, by reference, are maintained under '/dev/disk'
# See man pages fstab(5), findfs(8), mount(8) and/or blkid(8) for more info
#
UUID=f67055b0-03ba-4e15-a1e1-8124505d1d31 /                       xfs     defaults        0 0
# hello sed
UUID=76c059b7-1c58-429b-8936-ac34a749976d /boot                   xfs     defaults        0 0
# hello sed
UUID=2702f1d8-3154-4194-a25f-50c304d99e67 swap                    swap    defaults        0 0
# hello sed

追加的内容可使用 \n 作换行符,从而实现多行追加。

i 插入文本

i \<text> 命令可以把给定的 text 文本插入到每一个符合条件的行前面。
例 1:给 /etc/fstab 中每一个以 UUID 开头的行的前面插入一个 # hahaha

$ sed '/^UUID/i \# hahaha' /etc/fstab

#
# /etc/fstab
# Created by anaconda on Tue Dec  3 20:47:57 2019
#
# Accessible filesystems, by reference, are maintained under '/dev/disk'
# See man pages fstab(5), findfs(8), mount(8) and/or blkid(8) for more info
#
# hahaha
UUID=f67055b0-03ba-4e15-a1e1-8124505d1d31 /                       xfs     defaults        0 0
# hahaha
UUID=76c059b7-1c58-429b-8936-ac34a749976d /boot                   xfs     defaults        0 0
# hahaha
UUID=2702f1d8-3154-4194-a25f-50c304d99e67 swap                    swap    defaults        0 0   

c 替换文本

c \<text> 命令替换每一个符合条件的行为给定的 text 文本。
例 1:把 /etc/fstab 中每一个以 # 开头的行替换为 # 这是注释行

$ sed '/^#/c \# 这是注释行' /etc/fstab 

# 这是注释行
# 这是注释行
# 这是注释行
# 这是注释行
# 这是注释行
# 这是注释行
# 这是注释行
UUID=f67055b0-03ba-4e15-a1e1-8124505d1d31 /                       xfs     defaults        0 0
UUID=76c059b7-1c58-429b-8936-ac34a749976d /boot                   xfs     defaults        0 0
UUID=2702f1d8-3154-4194-a25f-50c304d99e67 swap                    swap    defaults        0 0

w 写入文件

w <file> 命令可以将每一个符合条件的行另存到 file 指定的文件中。
例 1:把 /etc/fstab 中每一个以 UUID 开头的行保存到 fstab_uuid.txt 中。

$ sed '/^UUID/w fstab_uuid.txt' -n /etc/fstab 
$ cat fstab_uuid.txt 
UUID=f67055b0-03ba-4e15-a1e1-8124505d1d31 /                       xfs     defaults        0 0
UUID=76c059b7-1c58-429b-8936-ac34a749976d /boot                   xfs     defaults        0 0
UUID=2702f1d8-3154-4194-a25f-50c304d99e67 swap                    swap    defaults        0 0

= 显示行号

= 命令可以在每一个符合条件的行的上方添加一个行号显示。
例 1:在 /etc/fstab 中的每一个以 UUID 开头的行的上方显示一个行号。

$ sed '/^UUID/=' /etc/fstab

#
# /etc/fstab
# Created by anaconda on Tue Dec  3 20:47:57 2019
#
# Accessible filesystems, by reference, are maintained under '/dev/disk'
# See man pages fstab(5), findfs(8), mount(8) and/or blkid(8) for more info
#
9
UUID=f67055b0-03ba-4e15-a1e1-8124505d1d31 /                       xfs     defaults        0 0
10
UUID=76c059b7-1c58-429b-8936-ac34a749976d /boot                   xfs     defaults        0 0
11
UUID=2702f1d8-3154-4194-a25f-50c304d99e67 swap                    swap    defaults        0 0

r 读取文件

r <file> 命令能够把指定文件中的内容追加到的每一个符合条件的行后。
例 1:把 /etc/resolv.conf 中的内容追加到 /etc/fstab 中第 2 行的后面。

$ sed '2r /etc/resolv.conf' /etc/fstab

#
# Generated by NetworkManager
nameserver 10.0.1.254
# /etc/fstab
# Created by anaconda on Tue Dec  3 20:47:57 2019
#
# Accessible filesystems, by reference, are maintained under '/dev/disk'
# See man pages fstab(5), findfs(8), mount(8) and/or blkid(8) for more info
#
UUID=f67055b0-03ba-4e15-a1e1-8124505d1d31 /                       xfs     defaults        0 0
UUID=76c059b7-1c58-429b-8936-ac34a749976d /boot                   xfs     defaults        0 0
UUID=2702f1d8-3154-4194-a25f-50c304d99e67 swap                    swap    defaults        0 0

! 地址定界取反

在命令前使用 ! 可对地址定界取反。
例 1:删除 /etc/fstab 中不以 ^UUID 开头的行。

$ sed '/^UUID/!d' /etc/fstab 
UUID=f67055b0-03ba-4e15-a1e1-8124505d1d31 /                       xfs     defaults        0 0
UUID=76c059b7-1c58-429b-8936-ac34a749976d /boot                   xfs     defaults        0 0
UUID=2702f1d8-3154-4194-a25f-50c304d99e67 swap                    swap    defaults        0 0

sed '/^UUID/p' fstab -n 效果相同。

s 查找替换

格式同 VIM 中的相同,s/被替换的内容/新内容/选项,分隔符也可不使用 / 自己定义。
选项有如下即可:

  • g:默认只替换每行查找过程中第一次出现的内容,可通过 g 指定选项实现行内全局替换;
  • p:显示替换成功的行;
  • w <file>:将匹配替换后的结果保存到 file 中;

例 1:替换 /etc/fstab 中所有 UUIDuuid 并仅显示被替换的行。

$ sed 's/UUID/uuid/gp' /etc/fstab -n
uuid=f67055b0-03ba-4e15-a1e1-8124505d1d31 /                       xfs     defaults        0 0
uuid=76c059b7-1c58-429b-8936-ac34a749976d /boot                   xfs     defaults        0 0
uuid=2702f1d8-3154-4194-a25f-50c304d99e67 swap                    swap    defaults        0 0

例 2:给 /etc/passwd 中匹配 r..t 的内容后加上 er,且仅显示修改的行。

$ sed 's/r..t/&er/gp' /etc/passwd -n
rooter:x:0:0:rooter:/rooter:/bin/bash
operator:x:11:0:operator:/rooter:/sbin/nologin
ftp:x:14:50:FTP User:/var/fterp:/sbin/nologin
dockerrooter:x:998:995:Docker User:/var/lib/docker:/sbin/nologin

进阶命令

在上面基本使用中只用到了模式空间,而下面就要介绍一下 sed 的保持空间的使用。
关于保持空间的操作要使用到下面几个命令:

  • h:把模式空间的内容覆盖至保持空间,原保持空间的内容将被清除;
  • H:把模式空间的内容追加至保持空间,而不覆盖原有保持空间内容;
  • g:从保持空间中取出内容覆盖至模式空间,原模式空间的内容将被清除;
  • G:从保持空间中取出内容追加至模式空间,而不覆盖原有模式空间内容;
  • x:把模式空间的内容与保持空间的内容互换;
  • n:读取匹配到的行的下一行到模式空间;
  • N:追加匹配到的行的下一行到模式空间;
  • d:删除模式空间中的行;
  • D:删除多行模式空间中的所有行;

为方便后面测试创建测试文件 test.txt 如下:

1 32423dadewarea
2 faewdfaef
3 feaddfae
4 edaded 
5 faewdf 
6 feawdfeaw
7 eafea
8 deawd
9 daewdw

显示偶数行

$ sed 'n;p' test.txt -n
2 faewdfaef
4 edaded 
6 feawdfeaw
8 deawd

多个命令之间可以使用 ; 来分隔;
由于没有指定匹配规则,所以所有行都满足条件,每读到一行 n 命令就会把下一行覆盖至当前模式空间,所以最后输出的就是偶数行。

显示最后两行

$ sed '$!N;$!D' test.txt 
9 daewdw

每读取一行就将下一行追加到模式空间中,如果不是最后一行就删除,所以如果文件是偶数行时,保留的就是最后两行,如果文件是奇数行时,保留的就是最后一行。

逆向显示文件内容

$ sed '1!G;h;$!d' test.txt 

9 daewdw
8 deawd
7 eafea
6 feawdfeaw
5 faewdf 
4 edaded 
3 feaddfae
2 faewdfaef
1 32423dadewarea

在读取第一行时由于保持空间没有内容,所以使用 1!G 指定在第一行时不取保持空间的内容;
在读取最后一行时,由于最后要通过模式空间输出内容,所以使用 $!d 指定在最后一行时不清空模式空间的内容;

显示最后一行

$ sed '$!d' test.txt 
9 daewdw

不是最后一行就执行删除模式空间的操作,所以最后模式空间中的内容就只剩最后一行。

给每行插入空行

$ sed 'G' test.txt 
1 32423dadewarea

2 faewdfaef

3 feaddfae

4 edaded 

5 faewdf 

6 feawdfeaw

7 eafea

8 deawd

9 daewdw

每读取一行就将保持空间的内容追加至模式空间,而保持空间不存在内容,所以每次追加的就是空行。

合并空白行并给每行插入空行

$ cat test.txt -A
1 32423dadewarea$
2 faewdfaef$
$
$
$
3 feaddfae$
4 edaded $
$
5 faewdf $
$
$
6 feawdfeaw$
7 eafea$
8 deawd$
9 daewdw$
$ sed '/^$/d;G' test.txt 
1 32423dadewarea

2 faewdfaef

3 feaddfae

4 edaded 

5 faewdf 

6 feawdfeaw

7 eafea

8 deawd

9 daewdw

显示奇数行

$ sed 'n;d' test.txt
1 32423dadewarea
3 feaddfae
5 faewdf 
7 eafea
9 daewdw

每读取一行就删除下一行,最后只保留了奇数行。

步进

sed 命令可使用 <起始值>~<步长> 来指定步进操作。
显示奇数行:

$ sed '1~2p' -n test.txt 
1 32423dadewarea
3 feaddfae
5 faewdf 
7 eafea
9 daewdw

显示偶数行:

$ sed '2~2p' -n test.txt 
2 faewdfaef
4 edaded 
6 feawdfeaw
8 deawd

练习

1、删除 /etc/grub2.cfg 文件中所有以空白开头的行首的空白。

sed 's/^[[:space:]]\+//' /etc/grub2.cfg

2、删除 /etc/fstab 文件中所有以 # 开头,后面至少跟一个空白字符的行的行首的 # 和空白字符。

sed 's/^#[[:space:]]\+//' /etc/fstab

3、echo 一个绝对路径给 sed 命令,取出其基名和目录名。
目录名:

echo `which wget` | sed 's@[^/]\+/\?$@@'

基名:

echo `which wget` | sed -r 's@(^/.*)/(.+)$@\1/@'
0

评论区