一、多行命令
概述
sed 编辑器的基础命令都是对一行文本进行操作。如果要处理的数据分布在多行中,sed基础命令是没办法处理的。
幸运的是,sed编辑器的设计人员已经考虑了这个问题的解决方案。sed编辑器提供了3个处理多行文本的特殊命令。
命令 | 描述 |
---|---|
N | 加入数据流的下一行,创建一个多行组进行处理 |
D | 删除多行组中的一行 |
P | 打印多行组中的一行 |
1.1 next命令
使用多行next(N)命令前先看一下单行next(n)是如果工作的。
1.1.1 单行next(n)命令
默认情况下,sed编辑器是从数据流中读出一行数据,然后用命令列表中的命令依次处理这一行数据。所有命令执行完后,取下一行数据重复上述过程。
单行next命令告诉sed编辑器跳过当前行,直接移动到数据流的下一行,并且只执行 单行next命令之后的命令。
例:删除首行之后的空行
$ cat < data1
header line
data line 1
End of data line
### 不使用next命令会将所有的空行都删除
$ sed '/^$/d' data1
header line
data line 1
End of data line
$ sed '/header/{n;d}' data1
header line
data line 1
End of data line
1.1.2 多行next(N)命令
多行next(N)命令会将下一行数据追加到正在处理数据(模式空间)中,文本仍然以换行符分隔。
$ cat <data1
header line
data line 1
End of data line
$ sed '/header/{N;s/\n//}' data1
header linedata line 1
End of data line
这个例子中,sed先查找包含header 的行 “header line”,然后将下一行 “data line 1” 追加到当前数据中,再删除换行符。
处理分散在两行中的短语时,使用N命令非常方便。
$ cat < data2
The linux System
Admin group metting will be held.
$ sed -n '/System.Admin/p' data2
$ sed -n '{N;/System.Admin/p}' data2
The linux System
Admin group metting will be held.
1.2 多行删除命令(D)
多行删除命令(D),删除多行数据的第一行。
$ cat <data2
The linux System
Admin group metting will be held.
#d命令将两行全部删除了
$ sed '{N;/System.Admin/d}' data2
#D命令只删除了第一行
ubuntu@VM-8-14-ubuntu:~$ sed '{N;/System.Admin/D}' data2
Admin group metting will be held.
1.3 多行打印命令( P)
与D命令相似。P命令只打印多行数据中的一行。
#p命令将两行全部打印出来
$ sed -n '{N;/System.Admin/p}' data2
The linux System
Admin group metting will be held.
#P命令只打印一行
$ sed -n '{N;/System.Admin/P}' data2
The linux System
P命令的强大之处体现在与N命令和D命令配合使用的时候。
$ cat <data3
Header line@
@
data line #1
data line #2@
@
End of data line
$ sed -n '{N;s/@\n@//;P;D}' data3
Header line
data line #1
data line #2
End of data line
- 读入 Header line@
- 执行N命令,将 \n@将加入到**Header line@**中。当前数据为 Header line@\n@
- 执行 s 命令,将 **@\n@**替换成空。当前数据为 Header line
- 打印Header line
- 删除模式空间中的第一行(Header line),继续执行N命令。
D命令的强大之处在于,删除模式空间的第一行后会强制sed编辑器返回到脚本的起始处。
二、保留空间
模式空间:是一块活跃的缓存区,在sed 编辑器 执行命令时保存待检查的文本。
sed 编辑器还有另外一块缓存区 保留空间。当你在处理模式空间中的某些数据时,可以将数据暂时存在保留空间。
命令 | 描述 |
---|---|
h | 将模式空间复制到保留空间 |
H | 将模式空间追加到保留空间 |
g | 将保留空间复制到模式空间 |
G | 将保留空间追加到模式空间 |
x | 交换模式空间和保留空间的内容 |
$ cat <data1
header line
data line 1
End of data line
$ sed -n '/header/{h;p;n;p;g;p}' data1
header line
data line 1
header line
- 找到包含 header的行 header line
- h将模式空间复制到保留空间,现在模式空间和保留空间内容一样(header line)
- p打印模式空间内容
- n 移到下一行数据 data line 1,现在模式空间是 data line 1,保留空间是 header line*
- p 打印 模式空间内容
- g 将保留空间复制到模式空间,现在模式空间和保留空间内容一样(header line)
- p 打印模式空间内容
三、 排除命令
感叹号 ! 命令用于排除命令,也就是让原来的命令失效
$ cat < data1
header line
data line 1
End of data line
$ sed -n '/header/p' data1
header line
$ sed -n '/header/!p' data1
data line 1
End of data line
正常情况下, p打印包含header的行。
使用排除命令后,!p打印不包含header的行。
例:倒序输出文件内容
$ cat <data1
header line
data line 1
End of data line
sed -n '{1!G;h;$p}' data1
End of data line
data line 1
header line
- 1!G :从第二行开始,将保留空间的内容追加到模式空间。
- h :将模式空间的内容复制到保留空间
- $p :处理到最后一行时 打印模式空间内容。
四、 改变执行流程
通常sed会从第一条命令开始执行,一直执行到最后一条命令。
sed 编辑器 提供了一种可以改变命令执行顺序的方法。
4.1 分支
分支命令(b)格式
[address] b [blabel]
address 决定了那些行会触发分支命令。
label 决定了跳转到的位置
$ cat <data1
header line
data line 1
End of data line
#跳过前两行
$ sed -n '{1,2b;p}' data1
End of data line
$ cat < data1
header line
data line 1
End of data line
#如果匹配data line 1,则跳到:jump处执行。否则顺序执行。
sed '{/data line 1/b jump
s/data/replacement/;
:jump
s/data/replacement jump/}' data1
header line
replacement jump line 1
End of replacement line
去掉文本中的逗号
$ echo "1,2,3,4,5"| sed -n '{:begin s/,//; /,/b begin;p}'
12345
4.2 测试
和分支命令(b)类似,测试命令(t)也可以修改sed编辑器命令的流程。
命令格式: [address] t label
和分支命令(b)类似。没有label的情况下,如果测试成功,sed会跳到脚本结尾。
去掉文本中的逗号
$ echo "1,2,3,4,5"| sed -n '{:begin s/,//p; t begin}'
12,3,4,5
123,4,5
1234,5
12345
五、模式替换
5.1 & 符号
& 符号代表替换命令中的匹配模式
$ echo "I have a cat,I have a hat"| sed -n 's/.at/"&"/gp'
I have a "cat",I have a "hat"
5.2 替换单独的单词
sed 编辑器使用圆括号定义替换模式的子模式。反向引用有反斜线和数字组成。
\1 是第一个子模式,\2是第二个子模式。依次类推。
圆括号需要用反斜线转义
$ echo "I have a cat,I have a hat"| sed -n 's/\(.at\)/"\1"/gp'
I have a "cat",I have a "hat"
六、 在脚本中使用 sed
6.1 使用包装器
将倒序输出文件内容命令封装成包装器。
$ cat <reserver.sh
#/usr/bin/bash
sed -n '{1!G;h;$p}' $1
$ cat < data1
header line
data line 1
End of data line
$ ./reserver.sh data1
End of data line
data line 1
header line
6.2 重定向sed 输出
使用 $() 将sed的输出重定向到变量中。
cat <reserver.sh
#/usr/bin/bash
var=$(sed -n '{1!G;h;$p}' $1)
echo result=$var
$ ./reserver.sh data1
result=End of data line data line 1 header line
七、创建 sed 实用工具
7.1 加倍行间距
$ cat <data1
header line
data line 1
End of data line
$ sed -n '{$!G;p}' data1
header line
data line 1
End of data line
7.2 对可能有空行的文件加倍行间距
$ cat <data1
header line
data line 1
End of data line
ubuntu@VM-8-14-ubuntu:~$ sed -n '{/^$/d;$!G;p}' data1
header line
data line 1
End of data line
7.3 给文件中的行编号
cat <data1
header line
data line 1
End of data line
$ sed '=' data1|sed 'N;s/\n/\t/;'
1 header line
2 data line 1
3 End of data line
7.4 打印末尾行
打印文件后3行
$ cat<data3
line1
line2
line3
line4
line5
line6
line7
line8
$ sed '{:begin $q;N;4,$D;b begin}' data3
line6
line7
line8