一. sed 基础
sed 编辑器被称作流编辑器,它会在编辑器处理数据之前基于预先提供的一组规则来编辑数据流。在流编辑器将所有命令与一行数据匹配完毕后,它会读取下一行数据并重复这个过程。
sed 编辑器会依次执行如下操作:一次从输入中读取一行数据、根据所提供的编辑器命令匹配数据、按照命令修改流中的数据、将新的数据输出到 STDOUT。
(一). sed 命令格式
sed 命令的格式如下:sed options script file。选项允许修改 sed 命令的行为,而 script 参数指定了应用于流数据上的单个命令。
选项 | 描述 |
---|---|
-e script | 在处理输入时,将 script 中指定的命令添加到已有的命令中 |
-f file | 在处理输入时,将 file 中指定的命令添加到已有的命令中 |
-n | 不产生命令输出,使用 print 命令来完成输出 |
二. sed 寻址模式
在 sed 编辑器中使用的命令默认会作用于文本数据的所有行。如果只想将命令作用于特定行或某些行,则必须用行寻址。
在 sed 编辑器中有两种形式的行寻址:以数字形式表示行区间、用文本模式来过滤出行。这两种形式都使用相同的格式来指定地址,也可以将特定地址的多个命令分组。sed 编辑器会将指定的每条命令作用到匹配指定地址的行上。
[address]command
address {
command1
command2
}
(一). 数字方式的行寻址
当使用数字方式的行寻址时,可以用行在文本流中的行位置来引用。 sed 编辑器会将文本流中的第一行编号为 1,然后继续按顺序为接下来的行分配行号。在命令中指定的地址可以是单个行号,或是用起始行号、逗号以及结尾行号指定的一定区间范围内的行。
$ sed '2s/dog/cat/' data.txt
The quick brown fox jumps over the lazy dog
The quick brown fox jumps over the lazy cat
The quick brown fox jumps over the lazy dog
The quick brown fox jumps over the lazy dog
$ sed '2,3s/dog/cat/' data.txt
The quick brown fox jumps over the lazy dog
The quick brown fox jumps over the lazy cat
The quick brown fox jumps over the lazy cat
The quick brown fox jumps over the lazy dog
$ sed '2,$s/dog/cat/' data.txt
The quick brown fox jumps over the lazy dog
The quick brown fox jumps over the lazy cat
The quick brown fox jumps over the lazy cat
The quick brown fox jumps over the lazy cat
(二). 使用文本模式过滤器
sed 允许指定文本模式来过滤出命令要作用的行。格式如下:/pattern/command,必须用斜线将要指定的模式封起来。 sed 会将命令作用到匹配指定文本模式的行。可以在文本模式中使用正则表达式来创建匹配效果更好的模式。
$ cat data.txt
root:x:0:0:root:/root:/bin/bash
daemon:x:2:2:daemon:/sbin:/sbin/nologin
operator:x:11:0:operator:/root:/sbin/nologin
$ sed '/daemon/s!/sbin/nologin!/bin/bash!' data.txt
root:x:0:0:root:/root:/bin/bash
daemon:x:2:2:daemon:/sbin:/bin/bash
operator:x:11:0:operator:/root:/sbin/nologin
(三). 命令组合
如果需要在单行上执行多条命令,可以用花括号将多条命令组合在一起。 sed 会处理地址行处列出的每条命令。
$ sed '2,3{
> s/dog/cat/
> s/brown/green/
> }' data.txt
The quick brown fox jumps over the lazy dog
The quick green fox jumps over the lazy cat
The quick green fox jumps over the lazy cat
The quick brown fox jumps over the lazy dog
三. sed 相关命令
(一). 替换命令
命令 s 会将斜线间指定的第二个文本字符串替换为第一个文本字符串模式。
$ cat data.txt
The quick brown fox jumps over the lazy dog.
The quick brown fox jumps over the lazy dog.
The quick brown fox jumps over the lazy dog.
$ sed 's/dog/cat/' data.txt
The quick brown fox jumps over the lazy cat.
The quick brown fox jumps over the lazy cat.
The quick brown fox jumps over the lazy cat.
1. 替换标记
替换命令在替换多行中的文本时能正常工作,但默认情况下它只替换每行中出现的第一处。要让替换命令能够替换一行中不同地方出现的文本必须使用替换标记。替换标记在替换命令字符串之后设置。
有 4 种可用的替换标记:
数字,表明新文本将替换第几处模式匹配的地方
g,表明新文本将会替换所有匹配的文本
p,表明原先行的内容要打印出来
w file,将替换的结果写到文件中
-n 选项将禁止 sed 编辑器输出。但 p 替换标记会输出修改过的行。w 替换标记会产生同样的输出,不过会将输出保存到指定文件中 (只有那些包含匹配模式的行才会保存在指定的输出文件中)。
$ cat data.txt
This is a test of the test script.
This is the second test of the test script.
$ sed 's/test/trial/2' data.txt
This is a test of the trial script.
This is the second test of the trial script.
$ sed 's/test/trial/g' data.txt
This is a trial of the trial script.
This is the second trial of the trial script.
cat data.txt
This is a test line.
This is a different line.
$ sed -n 's/test/trial/p' data.txt
This is a trial line.
$ sed 's/test/trial/w test.txt' data.txt
This is a trial line.
This is a different line.
$ cat test.txt
This is a trial line.
2. 替换字符
sed 编辑器允许选择其他字符来作为替换命令中的字符串分隔符。
$ cat data.txt
root:x:0:0:root:/root:/bin/bash
sync:x:5:0:sync:/sbin:/bin/sync
nscd:x:28:28:NSCD Daemon:/:/sbin/nologin
$ sed 's!/bin/bash!/bin/csh!' data.txt
root:x:0:0:root:/root:/bin/csh
sync:x:5:0:sync:/sbin:/bin/sync
nscd:x:28:28:NSCD Daemon:/:/sbin/nologin
(二). 删除行
可以使用命令 d 删除文本流中的特定行。它会删除指定的寻址模式匹配的所有行。
$ cat data.txt
This is line number 1.
This is line number 2.
This is line number 3.
This is line number 4.
$ sed '2d' data.txt
This is line number 1.
This is line number 3.
This is line number 4.
$ sed '2,3d' data.txt
This is line number 1.
This is line number 4.
$ sed '2,$d' data.txt
This is line number 1.
$ sed '/number 1/d' data.txt
This is line number 2.
This is line number 3.
This is line number 4.
可以使用两个文本模式来删除某个区间内的行。指定的第一个模式会 "打开" 行删除功能,第二个模式会 "关闭" 行删除功能。 sed 会删除两个指定行之间的所有行 (包括指定的行)。
只要 sed 在数据流中匹配到了开始模式,删除功能就会打开。这可能会导致意外的结果:如果没有找到停止模式,会将数据流中的剩余行全部删除。
$ sed '/2/,/3/d' data.txt
This is line number 1.
This is line number 4.
$ cat data.txt
This is line number 1.
This is line number 2.
This is line number 3.
This is line number 4.
This is line number 1 again.
This is text you want to keep.
This is the last line in the file.
$ sed '/1/,/3/d' data7.txt
This is line number 4.
sed '/2/,/5/d' data.txt
This is line number 1.
(三). 插入和附加文本
跟其他编辑器类似,sed 编辑器允许向数据流插入和附加文本行:
插入 (insert) 命令 i 会在指定行前增加一个新行
附加 (append) 命令 a 会在指定行后增加一个新行
sed '[address]command\new line'
$ sed '3i\New Line' data.txt
This is line number 1.
This is line number 2.
New Line
This is line number 3.
This is line number 4
$ sed '3a\New Line' data.txt
This is line number 1.
This is line number 2.
This is line number 3.
New Line
This is line number 4
(四). 修改行
命令 c 允许修改数据流中整行文本的内容。和插入和附加命令的工作机制一样,必须在 sed 命令中单独指定新行。
sed '[address]c\new line'
$ sed '3c\Changed Line' data.txt
This is line number 1.
This is line number 2.
Changed Line
This is line number 4
$ sed '/number 3/c\Changed Line' data.txt
This is line number 1.
This is line number 2.
Changed Line
This is line number 4
$ sed '2,3c\Changed Line' data.txt
This is line number 1.
Changed Line
This is line number 4
(五). 转换命令
命令 y 是唯一处理单个字符的 sed 命令,其会对 inchars 和 outchars 进行一对一映射。在 inchars 中的第一个字符会被转换为 outchars 中的第一个字符,第二个字符会被转换成 outchars 中的第二个字符。如果 inchars 和 outchars 的长度不同,则会产生一条错误消息。
[address]y/inchars/outchars/
$ cat data.txt
This is line number 1.
This is line number 2.
This is line number 3.
This is line number 4
$ sed 'y/123/789/' data.txt
This is line number 7.
This is line number 8.
This is line number 9.
This is line number 4
(六). 打印命令
命令 p 用来打印文本行。命令 = 用来打印行号。命令l (小写的 L) 用来列出行。
1. 打印行
跟替换命令中的 p 标记类似,命令 p 可以打印 sed 输出中的一行。在命令行上用 -n 选项,可以禁止输出其他行,只打印包含匹配文本模式的行。
$ sed -n '/number 3/p' data.txt
This is line number 3.
如果需要在修改之前查看行,也可以使用打印命令,比如与替换或修改命令一起使用。可以创建一个脚本在修改行之前显示该行。
$ sed -n '/number 3/{p; s/line/test/p}' data.txt
This is line number 3.
This is test number 3.
2. 打印行号
命令 = 会打印行在数据流中的当前行号。行号由数据流中的换行符决定。每次数据流中出现一个换行符,sed 编辑器会认为一行文本结束。
$ sed '=' data.txt
1
The quick brown fox jumps over the lazy dog.
2
The quick brown fox jumps over the lazy dog.
3
The quick brown fox jumps over the lazy dog.
4
The quick brown fox jumps over the lazy dog.
$ sed -n '/number 4/{=;p}' data.txt
4
This is line number 4
3. 列出行
列出 (list) 命令 l 可以打印数据流中的文本和不可打印的 ASCII 字符。任何不可打印字符要么在其八进制值前加一个反斜线,要么使用标准 C 风格的命名法。制表符的位置使用 \t 来显示。行尾的美元符表示换行符。如果数据流包含了转义字符,列出命令会在必要时候用八进制码来显示。
$ cat data.txt
This line contains tabs.
$ sed -n 'l' data.txt
This\tline\tcontains\ttabs.$
(七). 处理文件
1. 写入文件
使用 w 命令用来向文件写入行。格式如下:[address]w filename。filename 可以使用相对路径或绝对路径,运行 sed 编辑器的用户都必须有文件的写权限。如果不想让行显示到 STDOUT 上,可以用 sed 命令的 -n 选项。
$ sed '1,2w test.txt' data.txt
This is line number 1.
This is line number 2.
This is line number 3.
This is line number 4.
$ cat test.txt
This is line number 1.
This is line number 2.
2. 从文件读取数据
读取命令 r 允许将一个独立文件中的数据插入到数据流。filename 参数指定了数据文件的绝对路径或相对路径。在读取命令中使用地址区间,只能指定单独一个行号或文本模式地址。 sed 会将文件中的文本插到指定地址后。读取命令的格式如下:
[address]r filename
$ cat test.txt
This is an added line.
This is the second added line.
$ sed '3r test.txt' data.txt
This is line number 1.
This is line number 2.
This is line number 3.
This is an added line.
This is the second added line.
This is line number 4.
读取命令的另一个很酷的用法是和删除命令配合使用:利用另一个文件中的数据来替换文件中的占位文本。
$ cat test.txt
This is an added line.
This is the second added line.
$ sed '/number 3/{
r test.txt
d
}' data.txt
This is line number 1.
This is line number 2.
This is an added line.
This is the second added line.
This is line number 4.
四. sed 进阶
(一). 多行命令
sed 编辑器包含了 3 个可用来处理多行文本的特殊命令:
N:将数据流中的下一行加进来创建一个多行组来处理
D:删除多行组中的一行
P:打印多行组中的一行
1. next 命令
单行的 next 命令
小写的 n 命令会告诉 sed 移动到数据流中的下一文本行,而不用重新回到命令的最开始再执行一遍。通常 sed 在移动到数据流中的下一文本行之前,会在当前行上执行完所有定义好的命令,单行 next 命令改变了这个流程。
$ cat data.txt
This is the header line.
This is a data line.
This is the last line.
$
$ sed '/^$/d' data.txt
This is the header line.
This is a data line.
This is the last line.
$
$ sed '/header/{n;d}' data.txt
This is the header line.
This is a data line.
This is the last line.
合并文本行
多行版本的 next 命令 N 会将下一文本行添加到模式空间中已有的文本后,文本行仍然用换行符分隔。作用是将数据流中的两个文本行合并到同一个模式空间中。
$ cat data.txt
This is the header line.
This is the first data line.
This is the second data line.
This is the last line.
$ sed '/first/{N;s/\n/ /}' data.txt
This is the header line.
This is the first data line. This is the second data line.
This is the last line.
sed '/first/{N;N;s/\n//}' data.txt
This is the header line.
This is the first data line.This is the second data line.
This is the last line.
如果要在数据文件中查找一个可能会分散在两行中的文本短语的话,这是个很实用的应用程序。
$ cat data.txt
On Tuesday, the Linux System
Administrator's group meeting will be held.
All System Administrators should attend.
$ sed '{N
s/System Administrator/Desktop User/
s/System\nAdministrator/Desktop\nUser/
}' data.txt
On Tuesday, the Linux Desktop
User's group meeting will be held.
All System Administrators should attend.
$ sed '{
s/System Administrator/Desktop User/
N
s/System\nAdministrator/Desktop\nUser/
}' data.txt
On Tuesday, the Linux Desktop
User's group meeting will be held.
All Desktop Users should attend.
2. 多行删除命令
命令 d 用来删除模式空间中的当前行。但和命令 N 一起使用时,它会将模式空间中匹配的两行都删掉。
sed 提供了多行删除命令 D,它只删除模式空间中的第一行。该命令会删除到换行符 (含换行符) 为止的所有字符。
$ cat data.txt
On Tuesday, the Linux System
Administrator's group meeting will be held.
All System Administrators should attend.
$ sed '{N;/System\nAdministrator/d}' data.txt
All System Administrators should attend.
$ sed '{N;/System\nAdministrator/D}' data.txt
Administrator's group meeting will be held.
All System Administrators should attend.
3. 多行打印命令
命令 P 只打印多行模式空间中的第一行,这包括模式空间中直到换行符为止的所有字符。用 -n 选项来阻止脚本输出时,它和显示文本的单行 p 命令的用法大同小异。
$ cat data.txt
On Tuesday, the Linux System
Administrator's group meeting will be held.
All System Administrators should attend.
$ sed -n '{N;/System\nAdministrator/P}' data.txt
On Tuesday, the Linux System
二. 保持空间
模式空间是一块活跃的缓冲区,在 sed 执行命令时它会保存待检查的文本。但它并不是 sed 保存文本的唯一空间。sed 有另一块称作保持空间的缓冲区域。在处理模式空间中的某些行时,可以用保持空间来临时保存一些行。有 5 条命令可用来操作保持空间。
命令 | 描述 |
---|---|
h | 将模式空间复制到保持空间 |
H | 将模式空间附加到保持空间 |
g | 将保持空间复制到模式空间 |
G | 将保持空间附加到模式空间 |
x | 交换模式空间和保持空间的内容 |
$ cat data.txt
This is the header line.
This is the first data line.
This is the second data line.
This is the last line.
$ sed -n '/first/ {h ; p ; n ; p ; g ; p }' data.txt
This is the first data line.
This is the second data line.
This is the first data line.
三. 排除命令
感叹号命令 (!) 用来排除命令,让原本会起作用的命令不起作用。
$ cat data.txt
This is the header line.
This is the first data line.
This is the second data line.
This is the last line.
$ sed -n '/first/!p' data.txt
This is the header line.
This is the second data line.
This is the last line.
四. 改变流
sed 会从脚本的顶部开始,一直执行到脚本的结尾 (D 命令例外)。 sed 提供了一个方法来改变命令脚本的执行流程,其结果与结构化编程类似。
1. 分支
sed 提供了一种方法,可以基于地址、地址模式或地址区间排除一整块命令。这允许只对数据流中的特定行执行一组命令。分支命令 b 的格式如下:
[address]b [label]
address 参数决定了哪些行的数据会触发分支命令。label 参数定义了要跳转到的位置。如果没有加 label 参数,跳转命令会跳转到脚本的结尾。
$ cat data.txt
This is the header line.
This is the first data line.
This is the second data line.
This is the last line.
$
$ sed '{2,3b;s/This is/Is this/;s/line/line?/}' data.txt
Is this the header line?.
This is the first data line.
This is the second data line.
Is this the last line?.
要是不想直接跳到脚本的结尾,可以为分支命令定义一个要跳转到的标签。标签以冒号开始,最多 7 个字符长度。将指定的标签加到 b 命令后。使用标签允许跳过地址匹配处的命令,但仍然执行脚本中的其他命令。
$ sed '{
/first/b jump1
s/This is the/jump here on/
:jump1 s/This is the/no jump on/
}' data.txt
jump here on header line.
no jump on first data line.
jump here on second data line.
jump here on last line.`
$ echo "This, is, a, test, to, remove, commas." | sed -n '{
:start
s/,//1p
/,/b start
}'
This is, a, test, to, remove, commas.
This is a, test, to, remove, commas.
This is a test, to, remove, commas.
This is a test to, remove, commas.
This is a test to remove, commas.
This is a test to remove commas.
2. 测试
测试命令 t 可以用来改变 sed 脚本的执行流程。测试命令会根据替换命令的结果跳转到某个标签,而不是根据地址进行跳转。如果替换命令成功匹配并替换了一个模式,测试命令就会跳转到指定的标签。如果替换命令未能匹配指定的模式,测试命令就不会跳转。未指定标签的情况下,如果测试成功,sed 会跳转到脚本的结尾。
[address]t [label]
$ cat data.txt
This is the header line.
This is the first data line.
This is the second data line.
This is the last line.
$
sed '{
> s/first/matched/
> t
> s/This is the/No match on/
> }' data.txt
No match on header line.
This is the matched data line.
No match on second data line.
No match on last line.
五. 模式替代
1. & 符号
& 符号可以用来代表替换命令中的匹配的模式。不管模式匹配到的是什么样的文本,都可以在替代模式中使用 & 符号来使用这段文本。
$ echo "The cat sleep in his hat." | sed 's/.at/".at"/g'
The ".at" sleep in his ".at".
$ echo "The cat sleep in his hat." | sed 's/.at/"&"/g'
The "cat" sleep in his "hat".
2. 替代单独的单词
& 符号会提取匹配替换命令中指定模式的整个字符串,但有的时候只想提取这个字符串的一部分。sed 用圆括号来定义替换模式中的子模式。可以在替代模式中使用特殊字符来引用每个子模式。替代字符由反斜线和数字组成。数字表明子模式的位置。sed 会给第一个子模式分配字符 \1,给第二个子模式分配字符 \2,依此类推。
当在替换命令中使用圆括号时,必须用转义字符将它们标示为分组字符而不是普通的圆括号。这跟转义其他特殊字符正好相反。
$ echo "The System Administrator manual" | sed 's/\(System\) Administrator/\1 User/'
The System User manual
$ echo "1234567891" | sed '{
:start
s/\(.*[0-9]\)\([0-9]\{3\}\)/\1,\2/
t start
}'
1,234,567,891
六. 创建 sed 实用工具
1. 加倍行间距
$ cat data.txt
This is the header line.
This is the first data line.
This is the second data line.
This is the last line.
$ sed '$!G' data.txt
This is the header line.
This is the first data line.
This is the second data line.
This is the last line.
2. 对可能含有空白行的文件加倍行间距
$ cat data.txt
This is the header line.
This is the first data line.
This is the second data line.
This is the last line.
$
$ sed '{/^$/d;$!G}' data.txt
This is the header line.
This is the first data line.
This is the second data line.
This is the last line.
3. 给文件中的行编号
$ cat data.txt
This is the header line.
This is the first data line.
This is the second data line.
This is the last line.
$ sed '=' data.txt | sed '{N;s/\n/ /}'
1 This is the header line.
2 This is the first data line.
3 This is the second data line.
4 This is the last line.
4. 打印末尾行
$ cat data.txt
This is line 1.
This is line 2.
This is line 3.
This is line 4.
This is line 5.
This is line 6.
This is line 7.
This is line 8.
This is line 9.
This is line 10.
This is line 11.
This is line 12.
This is line 13.
This is line 14.
This is line 15.
$ sed ':start;{$q;N;11,$D};b start' data.txt
This is line 6.
This is line 7.
This is line 8.
This is line 9.
This is line 10.
This is line 11.
This is line 12.
This is line 13.
This is line 14.
This is line 15.
5. 删除行
删除连续的空白行
删除连续空白行的最简单办法是用地址区间来检查数据流。sed 会对所有匹配指定地址区间的行执行该命令。删除连续空白行的关键在于创建包含一个非空白行和一个空白行的地址区间。如果 sed 遇到了这个区间,它不会删除行。但对于不匹配这个区间的行,它会删除这些行。
$ cat data.txt
This is line one.
This is line two.
This is line three.
This is line four.
$
$ sed '/./,/^$/!d' data.txt
This is line one.
This is line two.
This is line three.
This is line four.
删除开头的空白行
$ cat data.txt
This is line one.
This is line two.
$
$ sed '/./,$!d' data.txt
This is line one.
This is line two.
6. 删除 HTML 标签
$ cat data.txt
<html>
<head>
<title>This is the page title</title>
</head>
<body>
<p>
This is the <b>first</b> line in the Web page.
This should provide some <i>useful</i>
information to use in our sed script.
</body>
</html>
$ sed 's/<[^>]*>//g;/^$/d' data.txt
This is the page title
This is the first line in the Web page.
This should provide some useful
information to use in our sed script.