sed 命令是 Linux 核心命令之一,熟悉 sed 命令可以让程序员在 Linux 环境下更加灵活的处理各种文本,做到事半功倍的效果,甚至再也不用打开文件逐行编辑。 笔者将个人对 sed 理解加以归纳整理,供大家学习借鉴,如果不当之处欢迎斧正。 首先介绍下 sed 命令的基本格式,万变不离其宗 其中 如果 所谓 address 就是定义将 command[flags] 用在特定行上 如果 address 为空,则 sed 逐行执行 command 数字方式行寻址 我们可以简单的使用 文本模式匹配寻址 从数据内容出发,支持正则匹配找到对应行。假设有文本 text1 内容 前三个例子是文本模式匹配,最后一个例子是正则匹配,表示匹配 This is 和 line 之间有四个 a-z 组成的字母的行,对正则表达式不清楚的伙伴可以参考我之前发到文章「Linux-正则表达式」,对此做了详细的说明 在寻址后面加上 替换命令是最常见之一,使用格式为 其中 pattern 支持正则匹配 在 target 使用 可以对 pattern 进行分组,在 target 中依次使用 flags 有四个可选项 数字,表明每一行将替换第几处匹配成功的地方 g, 表明新文本将会替换所有匹配的文本 p,表明原先行的内容要打印出来 w file,将替换的结果写入一个文件中 例如: 在 posix 规范的正则中,点号 pattern: target: 由于 sed 本身仅支持 BRE 规则,如果要使用分组功能,需要给小括号 对文本 text1(内容见上文) 做如下操作 每行只对第一个 is 替换成了 at 每行对第二个 is 替换成了 at 所有的 is 都替换成 at 将替换结果写入文件 test.out 中 当然,也可以用上寻址标识,只对特定行数执行替换命令 只针对第二行,将所有的 is 都替换成 at 删除命令,相对简单,即将当前行删掉 结合 插入命令,在指定行的前一行插入数据 这里在第二行之前插入了一个 new line 在所有带有 f 的行之前,都插入一个 new line 与 「插入」命令类似,只是在指定行后插入 在第二行之后插入一个 new line 可以理解为替换,用指定数据替换指定的行内容 可以看到第二行的内容被替换了 转换命令可以单独修改一个字符,比如 可以将 T 替换成 t , h 替换成 a 替换的两个参数长度必须严格相等,否则会报错如下所示 p 只是原封不动的打印选中的行(专业术语:模式空间) = 打印行数 l (小写的 L)打印完成的字符串,包括被转义的字符 为了演示方便,我们在 sed 命令后加一个 -n 参数,表示关闭自动输出到控制台的能力 这里的 写入 是一个 command,需要和下文中 flag 中的写入区分。 我们可以指定第几行写入到另一个文件中,格式为 我们将 第二行 和 第三行 内容写入到 test2 文件中 可以理解为,我们从另一个文件中读取内容,并且 append到指定行之后,格式为 我们将文件 test3 的内容 append 到了 test1 文件的最后一行。这里我们如果不加 address 部分,那么对 test1 文件的每一行都会 append 上 test3 文件的内容 sed 执行流程如下图所示: 所有的 command 都是针对上述的步骤 2 n 单行 next 命令 告诉 sed 编辑器移动到数据流中的下一文本行,而不用重新回到命令的最开始再执行一遍,整体流程就好像: 这里用到了多行命令,我们指定寻址文本中的第二行数据,先用 n ,将 sed 移动到下一行,执行 替换命令 N 合并文本行 单行 next 命令会将数据流中的下一文本行移动到 sed 编辑器的工作空间(称为模式空间 )。多行版本的 next 命令(用大写 N)会将下一文本行添加到模式空间中已有的文本后。 这样的作用是将数据流中的两个文本行合并到同一个模式空间中。文本行仍然用换行符分隔,但 sed 编辑器现在会将两行文本当成一行来处理。 可以理解为将文本内容的下一行附加到了模式空间中 假设我们有文本文件 test2 如下 我们想要替换 System Administrator 为 Desktop 这里可以用 N 命令将下一行附加到当前行处理,不过需要注意的是,linux 中每个换行出有个 D 多行删除命令 多行删除命令 D ,它只删除模式空间中的第一行。可以理解该命令会删除到换行符(含换行符)为止的所有字符。 只删了第一行数据(截止到 P 多行打印命令 多行打印命令(P )沿用了同样的方法。它只打印多行模式空间中的第一行,这包括模式空间中直到换行符为止的所有字符。 这里为了突出 P 命令的功能,我们给 sed 添加 -n 选项,屏蔽常规输出。 h 将模式空间复制到保持空间 H 将模式空间追加到保持空间 g 将保持空间复制到模式空间 G 将保持空间追加到模式空间 x 交换模式空间和保持空间内容 这些命令用来将文本从模式空间复制到保持空间。这可以清空模式空间来加载其他要处理的字符串。 通常,在使用 h 或 H 命令将字符串移动到保持空间后,最终还要用 g 、G 或 x 命令将保存的字符串移回模式空间(否则,你就不用在一开始考虑保存它们了)。 由于有两个缓冲区域,弄明白哪行文本在哪个缓冲区域有时会比较麻烦。这里有个简短的例子演示了如何用 h 和 g 命令来将数据在 sed 编辑器缓冲空间之间移动。 我们来一步一步看上面这个代码例子: sed 脚本在地址中用正则表达式来过滤出含有单词 first 的行; 当含有单词 first 的行出现时,h 命令将该行放到保持空间; p 命令打印模式空间也就是第一个数据行的内容; n 命令提取数据流中的下一行 (This is second line),并将它放到模式空间; p 命令打印模式空间的内容,现在是第二个数据行; g 命令将保持空间的内容(This is the first data line )放回模式空间,替换当前文本; p 命令打印模式空间的当前内容,现在变回第一个数据行了。 通过使用保持空间来回移动文本行,你可以强制输出中第一个数据行出现在第二个数据行后面。如果丢掉了第一个 p 命令,你可以以相反的顺序输出这两行。 这是个有用的开端。你可以用这种方法来创建一个 sed 脚本将整个文件的文本行反转 流程控制中的 「分支」 和 「测试」 本质上还是一种命令 之前提到过,sed 允许我们传入多个 command,这里再补充下,command 之间可以加一个 label (7 个字符以内),将命令分割开来。对于 b 命令,可以直接跳转到这个 label 位置,不用执行这个 label 之前的命令。 如上例, 如果 b 命令后没有 label,则这行数据不会执行任何命令(直接跳转到 commands 最后一行) 同理,如果 commands 中没有 b 后面的指定的 label,那么对应行数据也会得不到处理 如果 b 命令前不指定 address,意味着每一行都会尝试「跳转」 测试命令仅仅出现在替换命令中,如果替换命令发生替换(即 pattern 成功匹配),则触发跳转 如上例, 以上是 sed 的全部核心用法,根据上述内容,我们已经具备一些流式数据处理的能力了。比如有文本 tesst2 如下 每行之间有很多空行,看起来非常不美观,我们想删除所有的空行可以怎么这么做 如果我们在每一行后面,只想保留一个空行,可以这么做前言
基本格式
[address]command
command
可以有多个,形如[address]{
command
command
}address
为空,可直接省略花括号 {}
address
两种寻址方式
1,2,3,4
等表示第几行,且 2
表示选中第二行数据1,3
表示选中 1 ~ 3 行数据,闭区间1,">
表示从第一行到最后一行,闭区间This is first line
This is second line
This is third line
This is forth line/third/
可以匹配到第三行/f/
可以匹配第一行和第四行/first/,/third/
可以匹配 1 ~ 3 行,闭区间/^This is [a-z]{4} line1,3,4
行反向寻址
!
表明选取这段地址之外的行,比如2,3!
表示选取除了第二行和第三行之外的所有行/first/!
表示选取 2,3,4
行command
s 替换
s/pattern/target/[flags]
&
表示 pattern\1,\2
表示组位置echo "I have a cat" | sed 's/.at/<&>/'
输出为 I have a <cat>
.
表示任意字符,因此 pattern 部分可以匹配到 cat 字符。在 target 部分中,用 & 表示 pattern 即 cat,因为最终结果为用echo "I have a cat" | sed 's/c\(.*\)/h\1/'
输出为I have a hat
c\(.*\)
h\1
()
加上反斜线来转义,括号内部匹配任意字符串,这里分组匹配到了 at。在 target 部分,使用 \1
表示第一个分组内容,也就是 at,因此 pattern 部分组合起来就是 hat。⚡ root@dnvim ~/test sed 's/is/at/' test1
That is first line
That is second line
That is third line
That is forth line⚡ 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⚡ 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⚡ 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⚡ root@dnvim ~/test sed '2s/is/at/g' test1
This is first line
That at second line
This is third line
This is forth lined 删除
⚡ root@dnvim ~/test sed '1d' test1
This is second line
This is third line
This is forth lineaddress
部分内容可知 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⚡ 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 linea 附加
⚡ 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 linec 修改
⚡ 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 liney 转换
⚡ root@dnvim ~/test sed 'y/Th/ta/' test1
tais is first line
tais is second line
tais is taird line
tais is forta line⚡ root@dnvim ~/test sed 'y/Th/that/' test1
sed: -e expression #1, char 10: strings for `y' command are different lengthsp/=/l
打印⚡ 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 forth linew 写入[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 liner 读取
[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⚡ 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进阶
模式空间和保持空间
空间操作
操作模式空间
⚡ 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 lineOn Tuesday, the Linux System
Administrator's group meeting will be held.
All System Administrators should attend.
Thank you for your attendance.⚡ root@dnvim ~/test sed 'N; s/System\nAdministrator/Desktop/' test2
On Tuesday, the Linux Desktop's group meeting will be held.
All System Administrators should attend.
Thank you for your attendance.\n
符号⚡ root@dnvim ~/test sed 'N; /System\nAdministrator/D' test2
Administrator's group meeting will be held.
All System Administrators should attend.
Thank you for your attendance.\n
)⚡ root@dnvim ~/test sed -n 'N; /System\nAdministrator/P' test2
On Tuesday, the Linux System操作保持空间
⚡ 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⚡ root@dnvim ~/test sed -n '/first/ {h ; n ; p ; g ; p }' test1
This is second line
This is first line流程控制
command
分支
[address]b[label]
⚡ root@dnvim ~/test sed '{
3b jump1
s/T/t/
:jump1s/ is/ was/}' test1
this was first line
this was second line
This was third line
this was forth line3b jump1
表示在处理第三行的时候,command 直接跳转到 :jump1
位置, 忽略了 s/T/t/
这条命令测试
⚡ 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 lines/second/SECOND/
在第二行发生,触发了「测试跳转」,略过 s/T/t/
命令实战案例
⚡ 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 命令,将空行删除⚡ root@dnvim ~/test sed '/./,/^这里用到的是 正则匹配 + 地址取反 + 单行删除命令, 用
/./,/^">/
匹配「数据+一个空行」,地址取反,不符合这个规则的行,我们全部删除
这里看到文本末尾还是空行,如果想将末尾的空行删除,可以再加一个命令如下
⚡ root@dnvim ~/test sed -e '/./,/^d'
This is first line
This is second line
This is third line
This is forth line
这里接上管道符号,在下一个 sed 命令中,删除最后一行空白
本文使用 文章同步助手 同步