sed命令
简介:
sed是非交互式的编辑器。它不会修改文件,除非使用shell重定向来保存结果。默认情况下,所有的输出行都被打印到屏幕上。
sed编辑器逐行处理文件(或输入),并将结果发送到屏幕。具体过程如下: 首先sed把当前正在处理的行保存在一个临时缓存区中(也称为模式空间),然后处理临时缓冲区中的行,完成后把该行发送到屏幕上。sed每处理完一行就将其从临时缓冲区删除,然后将下一行读入,进行处理和显示。处理完输入文件的最后一行后,sed便结束运行。sed把每一行都存在临时缓冲区中,对这个副本进行编辑,所以不会修改原文件,除非使用 -i 选项会修改原文件。
sed 有两个内置的存储空间:
模式空间:模式空间用于 sed 命令执行的正常流程中。该空间 是sed 命令内置的一个缓冲区,用来存放、修改从输入文件读取的内容。
保持空间: 保持空间是另外一个缓冲区,用来存放临时数据。Sed 命令可以在保持空间和模式空间交换数据,但是不能在保持空间上执行普通的 sed 命令。每次循环读取数据过程中,模式空间的内容都会被清空,然而保持空间的内容则保持不变,不会在循环中被删除。
sed命令有两个内置的存储空间:
名称 | 概念 |
---|---|
模式空间(pattern space) | 模式空间用于 sed命令 执行的正常流程中。该空间是sed命令内置的一个缓冲区,用来存放、修改从输入文件读取的内容。 |
保持空间 (hold space) | 保持空间是另外一个缓冲区,用来存放临时数据。Sed命令可以在保持空间和模式空间交换数据,但是不能在保持空间上执行普通的 sed 命令。 |
相关选项:
n 输出模式空间行,读取下一行替换当前模式空间的行,执行下一条处理命令而非第一条命令。
N 读入下一行,追加到模式空间行,此时模式空间有两行内容。
h 把模式空间里的行复制到保持空间。
H 把模式空间里的行追加到保持空间。
g 用保持空间的内容替换模式空间的行。
G 把保持空间的内容追加到模式空间的行后面。
x 将保持空间的内容与模式空间里的当前行互换。
!对所选行以外的所有行应用命令。保持空间里默认存储一个空行。
可能应用于
- 处理多行模式空间( N、D、 P )
- 采用保持空间来保存模式空间的内容并使它可用于后续的命令 ( H、h、G、g、x)
- 编写使用分支和条件指令的脚本来更改控制流( :、b、t )
演示
N : 多行命令
多行Next (N)命令通过读取新的输入行,并将它添加到模式空间的现有内容之后来创建多行模式空间。模式空间最初的内容和新的输入行之间用换行符分隔。在模式空间中嵌入的换行符可以利用转义序列“\n”来匹配。在多行模式空间中,元字符“^”匹配空间中的第一个字条,而不匹配换行符后面的字符。同样,“$”只匹配模式空间中最后的换行符,而不匹配任何嵌入的换行符。在执行next命令之后,控制将被传递给脚本中的后续命令。
Next命令与next命令不同,next 输出模式空间的内容,然后读取新的输入行。next 命令不创建多行模式空间。
[root@localhost ~]# cat test
good morning
good noon
Good eve # 使用N命令前
ning
good night
[root@localhost ~]# sed '/Good/{N;s/\n//}' test
good morning
good noon
Good evening # 使用N命令输出后
good night
上面这个演示,用sed命令匹配到Good这行的文本在使用N将匹配到文本和下一行加入到模式空间,然后使用替换命令将换行符替换为空,结果就是在文件中的不完整的两行合并成了完整的一行。
delete: 删除命令
当遇到一个空行时,下一行就追加到模式空间中。然后试着匹配嵌入的换行符。注意定位元字符^和$分别匹配模式空间的开始处和结束处。
[root@localhost ~]# cat -n test # 原文件
1 good morning
2
3 good noon
4
5
6 Good evening
7
8
9
10 good night
[root@localhost ~]# sed '/^$/{N;/^\n$/d}' test # 使用d 命令输出结果
1 good morning
2
3 good noon
4 Good evening
5
6 good night
d 命令是当有偶数个空行时,所有的空行都会被删除。仅当有奇数个空行时,有一行被保留下来。这是因为删除命令清除的是整个模式空间。一旦遇到第一个空行,就读入下一行,并且两行都被删除。如果遇到第三个空行,并且下一行不为空,那么删除命令就不会被执行,因此空行被输出。
Delete : 多行删除命令
删除命令 d 删除模式空间的内容并会读入新的输入行,从而在脚本的顶端重新使用编辑方法。删除命令D 有些不同: 删除模式空间中直到第一个嵌入的换行符的这部分内容。它不会读入新的输入行,相反,它返回到脚本的顶端,将这些指令应用于模式空间剩余的内容,我们可以编写一个实现查找一系列空行并输出单个空行的脚本。
[root@localhost ~]# cat -n test # 原文件
1 good morning
2
3 good noon
4
5
6 Good evening
7
8
9
10 good night
[root@localhost ~]# sed '/^$/{N;/^\n$/D}' test
1 good morning
2
3 good noon
4
5 Good evening
6
7 good night
多行D 命令完成工作的原理是: 当遇到两个空行时,D 命令只删除两个空行中的第一个。下一次读取该脚本时,这个空行会被另一行读入模式空间。如果那行不为空,那么两行都输出,因此确保了输出一个空行。说白点就是,当模式空间中有两个空行时,只有第一个空行被删除,当一个空行后面跟有文本时,不对模式空间里的内容处理。
h: 将模式空间的内容复制到保持空间
H: 将模式空间的内容追加到保持空间
g: 将保持空间的内容复制到模式空间
G: 将保持空间的内容追加到模式空间
x: 把保持空间的内容和模式空间的内容进行交换
h,H,g,G使用:
[root@localhost ~]# cat test # 原文件
aaa
AAA
aaa
AAA
[root@localhost ~]# sed '/aaa/{h;d};/AAA/{G}' test #使用sed命令处理后
AAA
aaa
AAA
aaa
原文件是小写a在前面,通过sed命令(h)和(G)处理后,它们的位置调换了。如何实现的呢?:我们将第一行复制到保持空间(h),然后我们清除模式空间(d),然后sed将第二行读入模式空间,并且将保持空间的行追加(G)到模式空间的结尾,就有了处理后的结果。
b 分支命令
通常,sed 程序的执行过程会从第一个脚本命令开始,一直执行到最后一个脚本命令(D 命令是个例外,它会强制 sed 返回到脚本的顶部,而不读取新的行)。sed 提供了 b 分支命令来改变命令脚本的执行流程,其结果与结构化编程类似。
b 分支命令基本格式为:
[address]b [label]
其中,address 参数决定了哪些行的数据会触发分支命令,label 参数定义了要跳转到的位置。
需要注意的是,如果没有加 label 参数,跳转命令会跳转到脚本的结尾:
[root@localhost ~]# cat test
this is the first data line
this is the second data line
this is the header line
this is the last line
[root@localhost ~]# sed '{2,3b ; s/this is/Is this/ ; s/line/test/}' test
1 Is this the header test
2 this is the first data line
3 this is the second data line
4 Is this the last test
可以看到,上面例子中因为 b 命令未指定 label 参数,因此数据流中的第2行和第3行并没有执行那两个替换命令。
如果我们不想直接跳到脚本的结尾,可以为 b 命令指定一个标签(也就是格式中的 label,最多为 7 个字符长度)。在使用此该标签时,要以冒号开始(比如 :label2),并将其放到要跳过的脚本命令之后。这样,当 sed 命令匹配并处理该行文本时,会跳过标签之前所有的脚本命令,但会执行标签之后的脚本命令。
[root@localhost ~]# sed '{/first/b hello1 ; s/this is the/hello world to/
> :hello1
> s/this is the/Jump here on/}' test
hello world to header line
Jump here on first data line
hello world second data line
hello world last line
在上面这个例子中,如果文本行中出现了 first,程序的执行会直接跳到 hello1 标签之后的脚本行。如果分支命令的模式没有匹配,sed 会继续执行所有的脚本命令。
[root@master ~]# 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.
b 分支命令除了可以向后跳转,还可以向前跳转,例如:在这个例子中,当缓冲区中的行内容中有逗号时,脚本命令就会一直循环执行,每次迭代都会删除文本中的第一个逗号,并打印字符串,直至内容中没有逗号为止。