Linux-Sed 工具解析

前言

sed 命令是 Linux 核心命令之一,熟悉 sed 命令可以让程序员在 Linux 环境下更加灵活地处理各种文本,做到事半功倍的效果,甚至再也不用打开文件逐行编辑。

笔者将个人对 sed 理解加以归纳整理,供大家学习借鉴,如果不当之处欢迎斧正。

基本格式

首先介绍下 sed 命令的基本格式,万变不离其宗

[address]command

其中command 可以有多个,形如

[address]{
command
command
}

如果address 为空,可直接省略花括号{}

address

所谓 address 就是定义将 command[flags] 用在特定行上

如果 address 为空,则 sed 逐行执行 command

两种寻址方式

数字方式寻址

我们可以简单地使用1,2,3,4 等表示第几行,且$ 表示最后一行,比如

文本模式匹配寻址

从数据内容出发,支持正则匹配找到对应的属性。假设有文本 text1 内容

This is first line
This is second line
This is third line
This is forth line

前三个例子是文本模式匹配,最后一个例子是正则匹配,表示匹配 This is 和 line 之间有四个 a-z 组成的字母的行,对正则表达式不清楚的伙伴可以参考我之前发到文章「Linux-正则表达式」,对此做了详细的说明

反向寻址

在寻址后面加上!表明选取这段地址之外的行,比如

command

s 替换

替换命令是最常见之一,使用格式为

s/pattern/target/[flags]

例如:

在 posix 规范的正则中,点号.表示任意字符,因此 pattern 部分可以匹配到 cat 字符。 在 target 部分中,用 & 表示 pattern 即 cat,因为最终结果为用 替换了 原文中的 cat

pattern:c(.*)

target:h1

由于 sed 本身仅支持 BRE 规则,如果要使用分组功能,需要给小括号()加上反斜线来转义,括号内部匹配任意字符串,这里分组匹配到了 at。 在 target 部分,使用1表示第一个分组内容,也就是at,因此 pattern 部分组合起来就是 hat。

对文本 text1(内容见上文) 做如下操作

   root@dnvim   ~/test   sed 's/is/at/' test1
That is first line
That is second line
That is third line
That is forth line

每行只对第一个 is 替换成了 at

   root@dnvim   ~/test   sed 's/is/at/2' test1
This at first line
This at second line
This at third line
This at forth line

每行对第二个 is 替换成了 at

   root@dnvim   ~/test   sed 's/is/at/g' test1
That at first line
That at second line
That at third line
That at forth line

所有的 is 都替换成 at

   root@dnvim   ~/test   sed 's/is/at/gw test.out' test1
That at first line
That at second line
That at third line
That at forth line

   root@dnvim   ~/test   cat test.out
That at first line
That at second line
That at third line
That at forth line

将替换结果写入文件 test.out 中

当然,也可以用上寻址标识,只对特定行数执行替换命令

   root@dnvim   ~/test   sed '2s/is/at/g' test1
This is first line
That at second line
This is third line
This is forth line

只针对第二行,将所有的is 都替换成 at

d 删除

删除命令,相对简单,即将当前行删掉

   root@dnvim   ~/test   sed '1d' test1
This is second line
This is third line
This is forth line

结合address部分内容可知1d含义是将 第一行删除

   root@dnvim   ~/test   sed '/f/d' test1
This is second line
This is third line

/f/d是将带有 f 的行都删掉

   root@dnvim   ~/test   sed '/f/!d' test1
This is first line
This is forth line

/f/!d这里对地址取反,对于不含有f 的行都删掉

i 插入

插入命令,在指定行的前一行插入数据

   root@dnvim   ~/test   sed '2i This is new line' test1
This is first line
This is new line
This is second line
This is third line
This is forth line

这里在第二行之前插入了一个 new line

   root@dnvim   ~/test   sed '/f/i This is new line' test1
This is new line
This is first line
This is second line
This is third line
This is new line
This is forth line

在所有带有f的行之前,都插入一个 new line

a 附加

与 「插入」命令类似,只是在指定行后插入

   root@dnvim   ~/test   sed '2a This is new line' test1
This is first line
This is second line
This is new line
This is third line
This is forth line

在第二行之后插入一个 new line

c 修改

可以理解为替换,用指定数据替换指定的行内容

   root@dnvim   ~/test   sed '2c This is new line' test1
This is first line
This is new line
This is third line
This is forth line

可以看到第二行的内容被替换了

y 转换

转换命令可以单独修改一个字符,比如

   root@dnvim   ~/test   sed 'y/Th/ta/' test1
tais is first line
tais is second line
tais is taird line
tais is forta line

可以将 T 替换成 t , h 替换成 a

替换的两个参数长度必须严格相等,否则会报错如下所示

   root@dnvim   ~/test   sed 'y/Th/that/' test1
sed: -e expression #1, char 10: strings for `y' command are different lengths

p/=/l打印

p 只是原封不动的打印选中的行(专业术语:模式空间)

= 打印行数

l (小写的L)打印完成的字符串,包括被转义的字符

为了演示方便,我们在 sed 命令后加一个 -n 参数,表示关闭自动输出到控制台的能力

   root@dnvim   ~/test   sed -n 'p' test1
This is first line
This is second line
This is third line
This is forth line

   root@dnvim   ~/test   sed -n '=' test1
1
2
3
4

   root@dnvim   ~/test   sed -n 'l' test1
This is first line$
This is second line$
This is third line$
This is forth line$

w 写入

这里的 写入 是一个 command,需要和下文中 flag 中的写入区分。

我们可以指定第几行写入到另一个文件中,格式为[address]w file

   root@dnvim   ~/test   sed '2,3w test2' test1
This is first line
This is second line
This is third line
This is forth line

   root@dnvim   ~/test   cat test2
This is second line
This is third line

我们将 第二行 和 第三行 内容写入到 test2 文件中

r 读取

可以理解为,我们从另一个文件中读取内容,并且 append到指定行之后,格式为[address]r file

   root@dnvim   ~/test   cat test3
this is test3 file, line 1
this is test3 file, line 2

   root@dnvim   ~/test   sed '$r test3' test1
This is first line
This is second line
This is third line
This is forth line
this is test3 file, line 1
this is test3 file, line 2

我们将文件 test3 的内容 append 到了 test1 文件的最后一行。 这里我们如果不加 address 部分,那么对 test1 文件的每一行都会 append 上 test3 文件的内容

   root@dnvim   ~/test   sed 'r test3' test1
This is first line
this is test3 file, line 1
this is test3 file, line 2
This is second line
this is test3 file, line 1
this is test3 file, line 2
This is third line
this is test3 file, line 1
this is test3 file, line 2
This is forth line
this is test3 file, line 1
this is test3 file, line 2

进阶

模式空间和保持空间

sed 执行流程如下图所示:

  1. 从第一行开始(或者从 address 定义的地方开始),每读到一行,将该行内容写入模式空间
  2. sed 命令(command 部分) 处理 模式空间中的数据
  3. 如果sed 命令 options 中不带有 -n,则将 模式空间 中的数据打印到 console
  4. 清空模式空间,并且读取文本文件的下一行内容(或者 address 指定的下一行内容)
Linux-Sed 工具解析

空间操作

操作模式空间

所有的 command 都是针对上述的步骤2

n 单行next 命令

告诉sed编辑器移动到数据流中的下一文本行,而不用重新回到命令的最开始再执行一遍,整体流程就好像:

   root@dnvim   ~/test   sed '2{
quote> n
quote> s/This/That/
quote> }' test1

This is first line
This is second line
That is third line
This is forth line

这里用到了多行命令,我们指定寻址文本中的第二行数据,先用 n ,将 sed 移动到下一行,执行 替换命令

N 合并文本行

单行next 命令会将数据流中的下一文本行移动到sed编辑器的工作空间(称为模式空间 )。多行版本的next 命令(用大写N)会将下一文本行添加到模式空间中已有的文本后。

这样的作用是将数据流中的两个文本行合并到同一个模式空间中。文本行仍然用换行符分隔,但sed编辑器现在会将两行文本当成一行来处理。

可以理解为将文本内容的下一行附加到了模式空间中

假设我们有文本文件 test2 如下

On Tuesday, the Linux System
Administrator's group meeting will be held.
All System Administrators should attend.
Thank you for your attendance.

我们想要替换 System Administrator 为 Desktop

   root@dnvim   ~/test   sed 'N; s/System
Administrator/Desktop/' test2
On Tuesday, the Linux Desktop's group meeting will be held.
All System Administrators should attend.
Thank you for your attendance.

这里可以用 N 命令将下一行附加到当前行处理,不过需要注意的是,linux 中每个换行出有个 符号

D 多行删除命令

多行删除命令D ,它只删除模式空间中的第一行。可以理解该命令会删除到换行符(含换行符)为止的所有字符。

   root@dnvim   ~/test   sed 'N; /System
Administrator/D' test2
Administrator's group meeting will be held.
All System Administrators should attend.
Thank you for your attendance.

只删了第一行数据(截止到

P 多行打印命令

多行打印命令(P )沿用了同样的方法。它只打印多行模式空间中的第一行,这包括模式空间中直到换行符为止的所有字符。

   root@dnvim   ~/test   sed -n 'N; /System
Administrator/P' test2
On Tuesday, the Linux System

这里为了突出 P 命令的功能,我们给 sed 添加 -n 选项,屏蔽常规输出。

操作保持空间

这些命令用来将文本从模式空间复制到保持空间。这可以清空模式空间来加载其他要处理的字符串。

通常,在使用h 或H 命令将字符串移动到保持空间后,最终还要用g 、G 或x 命令将保存的字符串移回模式空间(否则,你就不用在一开始考虑保存它们了)。

由于有两个缓冲区域,弄明白哪行文本在哪个缓冲区域有时会比较麻烦。这里有个简短的例子演示了如何用h 和g 命令来将数据在sed编辑器缓冲空间之间移动。

   root@dnvim   ~/test   cat test1
This is first line
This is second line
This is third line
This is forth line
   root@dnvim   ~/test   sed -n '/first/ {h ; p ; n ; p ; g ; p }' test1
This is first line
This is second line
This is first line

我们来一步一步看上面这个代码例子:

  1. sed脚本在地址中用正则表达式来过滤出含有单词first的行;
  2. 当含有单词first的行出现时,h 命令将该行放到保持空间;
  3. p 命令打印模式空间也就是第一个数据行的内容;
  4. n 命令提取数据流中的下一行 (This is second line),并将它放到模式空间;
  5. p 命令打印模式空间的内容,现在是第二个数据行;
  6. g 命令将保持空间的内容(This is the first data line )放回模式空间,替换当前文本;
  7. p 命令打印模式空间的当前内容,现在变回第一个数据行了。

通过使用保持空间来回移动文本行,你可以强制输出中第一个数据行出现在第二个数据行后面。如果丢掉了第一个p 命令,你可以以相反的顺序输出这两行。

   root@dnvim   ~/test   sed -n '/first/ {h ; n ; p ; g ; p }' test1
This is second line
This is first line

这是个有用的开端。你可以用这种方法来创建一个sed脚本将整个文件的文本行反转

流程控制

流程控制中的 「分支」 和 「测试」 本质上还是一种命令command

分支

[address]b[label]

之前提到过,sed 允许我们传入多个 command,这里再补充下,command 之间可以加一个 label (7 个字符以内),将命令分割开来。对于 b 命令,可以直接跳转到这个 label 位置,不用执行这个 label 之前的命令。

   root@dnvim   ~/test   sed '{
3b jump1
s/T/t/
:jump1
s/ is/ was/}' test1
this was first line
this was second line
This was third line
this was forth line

如上例,3bjump1 表示在处理第三行的时候,command 直接跳转到:jump1 位置, 忽略了s/T/t/这条命令

如果 b 命令后没有 label,则这行数据不会执行任何命令(直接跳转到 commands 最后一行)

同理,如果 commands 中没有 b 后面的指定的 label,那么对应行数据也会得不到处理

如果 b 命令前不指定 address,意味着每一行都会尝试「跳转」

测试

测试命令仅仅出现在替换命令中,如果替换命令发生替换(即 pattern 成功匹配),则触发跳转

   root@dnvim   ~/test   sed '{
s/second/SECOND/
t jump1
s/T/t/
:jump1
s/ is/ was/
}' test1
this was first line
This was SECOND line
this was third line
this was forth line

如上例,s/second/SECOND/在第二行发生,触发了「测试跳转」,略过s/T/t/命令

实战案例

以上是 sed 的全部核心用法,根据上述内容,我们已经具备一些流式数据处理的能力了。比如有文本 tesst2 如下

   root@dnvim   ~/test   cat test2
This is first line



This is second line



This is third line




This is forth line

每行之间有很多空行,看起来非常不美观,我们想删除所有的空行可以怎么这么做

   root@dnvim   ~/test   sed '/^$/d' test2
This is first line
This is second line
This is third line
This is forth line

这里用到了 正则匹配 + 单行删除命令, 用/^$/匹配所有空行,然后用 d 命令,将空行删除

如果我们在每一行后面,只想保留一个空行,可以这么做

   root@dnvim   ~/test   sed '/./,/^$/!d' test2
This is first line

This is second line

This is third line

This is forth line

这里用到的是 正则匹配 + 地址取反 + 单行删除命令, 用/./,/^$/匹配「数据+一个空行」,地址取反,不符合这个规则的行,我们全部删除

这里看到文本末尾还是空行,如果想将末尾的空行删除,可以再加一个命令如下

   root@dnvim   ~/test   sed -e '/./,/^$/!d' test2 | sed '$d'
This is first line

This is second line

This is third line

This is forth line

这里接上管道符号,在下一个sed 命令中,删除最后一行空白

展开阅读全文

页面更新:2024-05-09

标签:空行   正则   字符   文本   命令   模式   文件   工具   内容   数据   空间

1 2 3 4 5

上滑加载更多 ↓
推荐阅读:
友情链接:
更多:

本站资料均由网友自行发布提供,仅用于学习交流。如有版权问题,请与我联系,QQ:4156828  

© CopyRight 2008-2024 All Rights Reserved. Powered By bs178.com 闽ICP备11008920号-3
闽公网安备35020302034844号

Top