sed入门介绍

一、sed工作原理概述

  原理这东西本身是说的越简单越好,可是发现自己无法用简单精辟的语言来描绘,于是借用一下官方的描述并对其进行的简要字面的意译:

原文:
sed maintains two data buffers: the active pattern space, and the auxiliary hold space. Both are initially empty.

sed operates by performing the following cycle on each line of input: first, sed reads one line from the input 
stream, removes any trailing newline, and places it in the pattern space. Then commands are executed; 
each command can have an address associated to it: addresses are a kind of condition code, and a command 
is only executed if the condition is verified before the command is to be executed.

When the end of the script is reached, unless the -n option is in use, the contents of pattern space are 
printed out to the output stream, adding back the trailing newline if it was removed. Then the next cycle starts 
for the next input line.

Unless special commands (like ‘D’) are used, the pattern space is deleted between two cycles. 
The hold space, on the other hand, keeps its data between cycles (see commands ‘h’, ‘H’, ‘x’, ‘g’, ‘G’ to 
move data between both buffers).

译文:
        sed维护两个数据缓冲区:活动中的模式空间和辅助的保持空间。两个区域最开始默认都没有数据。
        sed每读入一行文本都要执行以下的循环步骤:首先,sed会从输入流中读入一行,去掉其末尾的换行符,
并把它加载到模式空间中。然后,sed会执行命令,每个命令都可以有与之关联的地址。地址是作为条件
判断代码来用的,是否要执行命令要取决于对应地址判断。
        当包含命令的脚本已经执行达到末尾(就是命令都执行完了,对读入进模式空间的当前行),除非显式使用-n选
项,否则,默认模式空间中的内容会被打印输出到标准输出流中并且会加上行尾的换行符。一行处理
完成后,会开始下一个循环去处理接下来的一行。
        除非特殊的命令(比如像D)被使用,因为这类命令会删除模式空间中的内容。另外值得一提的是,保持空间,
可以在读文本处理循环之间用于保存数据,可以了解命令(h,H,x,g,G这些命令会对模式空间和保持空间之间的
数据进行来回移动和处理)。

  看了上面的原理,可能大家还是一头雾水。简单来说,sed的处理模式类似于早期的ed编辑器,
ed编辑器是交互式的等待用户的命令输入,命令输入会对已经加载到ed的缓冲区中的文本进行编辑处理。
sed的前身也是ed编辑器,不过sed做了一些改善,它的工作机理也是类似于如此,sed是根据你给定的脚本
命令,然后一行一行的处理文本。

请看下面的两张图:

sed入门介绍_第1张图片

sed入门介绍_第2张图片

  对于初学者,最初,建议先不要碰和hold space相关的命令,可以先理解清楚常用选项
和pattern space相关的命令之后,再对hold space的引入对比学习。

二、sed的通用选项

2.1、常用选项

语法结构:
sed [OPTION]... {script-only-if-no-other-script} [input-file]...
或者写成:
sed [OPTION]... 'script' [input-file]...

OPTION表示sed配合使用的选项,可以省略,可以有多个,可以有长短选项;
script表示包含处理命令的脚本,语法非常复杂,变化多样,下面会介绍;
input-file表示sed处理的文本,如果省略了,表示从标准输入流中读,也可以通过管道把文本流
传递给sed来处理;其中有个特殊的选项。
如果-e,--expression,-f,--file选项指定了,命令行传递的第一个非选项参数会作为sed的脚本或包含脚本的文件,
其后的非选项参数才表示待处理的文件名;

--help:
display this help and exit
显示sed的帮助信息并正常退出(命令退出状态是0);

--version:
output version information and exit
打印版本信息并正常退出;

-n, --quiet, --silent:
suppress automatic printing of pattern space
抑制模式空间的输出;(工作原理章节,默认模式空间内容在处理完成后会以默认的行为打印到标准输出流);

-e script, --expression=script:
add the script to the commands to be executed
连接多个执行脚本,多点编辑;

-f script-file, --file=script-file:
add the contents of script-file to the commands to be executed
脚本文件中存储sed的编辑命令(每行一个编辑命令);

-i[SUFFIX], --in-place[=SUFFIX]:
edit files in place (makes backup if SUFFIX supplied)
直接编辑处理源文件(加上后缀可以指定备份);

-r, --regexp-extended:
use extended regular expressions in the script.
脚本中支持使用扩展正则表达式的语法;

2.2、其他选项

-c, --copy:
use copy instead of rename when shuffling files in -i mode
只有在使用-i配置特定备份后缀的时候,-c才有用。加上-c选项后,例如(sed -ci.bak '1d' test),这样备份文件
test.bak的属性属主和属组为特定执行sed用户的,权限没有变(是以特定用户通过类似于cp的方式去备份的文件)
而源文件是直接修改的,然后编辑修改后,权限没有变,而且文件属主和属组也不变,刚好和-i加后缀不加-c项
不同。要注意权限,复制的权限和上边mv的权限是不一样的,不仅仅要考虑文件本身权限,还要考虑文件所属
目录的权限。

-l N, --line-length=N:
specify the desired line-wrap length for the `l' command
可以控制指定地址行的行字符数长度,N表示控制从第几个字符开始。
用有如下形式:
sed -n -l 11 '1l' newsedtxt,这个表示对文本1的第一行进行输出,在命令选项中要明确申明命令"l",
这样就会用-l选项指定的字符长度(行容纳N-1个字符),如果命令l的后边带上数字,表示以这个数字为准,例如
sed -n -l 11 '1l2' newsedtxt,这样会以每行一个字符为准。行尾会带上符号"\",原本的本文句尾的换行符$也算
一个字符了。本文中如果有横向制表符也会显式打印成\t(经过测试貌似算2个字符,具体没有深究),其他特殊字符
也没有测试,如果文本注解有误,希望得到大家的纠正。

--posix:
disable all GNU extensions.
禁用所有的GNU扩展选项。

-s, --separate:
consider files as separate rather than as a single continuous long stream.
默认sed的形式为,如果有多个文件,会把所有行读出来,作为缓冲区中的一长串的流,比如我有两个
文件,这时如果要分别显示他们的第一行的内容,默认不加-s,只会对第一个文件(命令行写入的先后顺序)
的第一行内容进行输出。加上-s会,会多个文件作为分离的而非一个整体,这样会打印2行内容。
例如:
sed -n '1p' newsedtxt sedtxt
sed -ns '1p' newsedtxt sedtxt
可以自己准备两个文本测试。

-u, --unbuffered:
load minimal amounts of data from the input files and flush the output buffers more often
从输入文件装载最少的数据,并且刷新输出缓冲区,也就是说尽量少缓冲input和output 要随时更新。
这个涉及处理效率的问题了,不影响输出结果。

-z, --null-data:
separate lines by NUL characters
默认情况下,SED对每一行使用换行符分割,如果提供了该选项的话,它将使用NULL字符分割行
可以自己查阅何为NULL字符,用的较少。

三、sed的脚本

3.1、sed的脚本使用预览

假设没有-e,-f,--expression,--file选项,sed的脚本可以理解为以下形式:
[addr]X[options]
X表示sed的单个命令;
addr表示一个附加的行地址;如果指定了地址addr,addr可以匹配对应的行,而地址后面的命令X,
会只会针对这些行文本进行处理。这个地址可以是一个单独的数字(表示具体行编号),或者是一个
常规的表达式,或者是地址范围。
options表示sed的执行命令X的一些附加选项;

例如:
sed '30,35d' intput.txt
这个例子,其中的30,35表示地址表达式,表示第30行和第35行;
d表示sed的命令,用于删除模式空间中的内容;
组合在一起即为30行和35行,从模式空间中删除,不打印到标准输出;

3.2、sed命令总结

1、a \text
表示在指定地址后面一行追加指定的文本text,支持使用"\n"来实现多行追加;
2、a text 
和a \text一样;
3、c\ text
用给定的文本"text"替换指定地址的行内容;
4、c text
和c\ text用法一样;
5、i\ text 
在给定地址匹配的行前面插入指定的文本"text";
6、i text
和i\ text以用法一样;
7、d
删除模式空间中的内容,立即开始下一个循环;
8、D
D命令是删除当前模式空间开端至第一个换行符\n之间的内容并放弃之后的命令,
但是对剩余模式空间重新执行sed的脚本;
9、e
把从模式空间中读入的内容当作外部shell的命令,然后把执行的结果替换模式空间的内容,
最终打印到输出流的内容即为外部命令执行的结果,如果有换行符,会被移除;
10、e command
执行指定的外部命令,并把命令执行的输出结果发送给输出流。命令可以跨多行,不过最后一个结尾要用
反斜线运行。
11、h 
用模式空间中的内容替换保持空间中的内容。(覆盖写)
12、H
给保持空间中的内容追加一个换行符号,然后把模式空间中的内容写入到保持空间的结尾。
即为利用模式空间中的内容追加写入保持空间中。
13、l
以一种明确的方式打印模式空间,比如显示行尾的换行符,比如把横向制表符显示成\t,等等;
14、n
如果没有抑制模式空间的输出,会输出模式空间中的内容,并且,把模式空间中的下一行的内容,替换
当前模式空间中的内容。如果n请求没有下一行(文本已经处理到最后一行),sed后续的命令不再执行;
即:覆盖匹配到的行的下一行至模式空间中;
15、N
给模式空间追加一个换行符,并且把输入流文本的下一行写入到模式空间中,以追加的方式。
如果sed处理的输入流文本,没有了下一行,将不会执行后续的sed命令,直接退出;
即: 追加读取匹配到的行的下一行至模式空间中;
16、p
打印当前模式空间中的内容到输出流;
17、P
打印模式空间中的第一行;
18、q[exit-code]
立即退出sed,不会处理余下的内容和命令;(先把模式空间中的内容打印输出,然后再退出)
19、Q[exit-code]
和q的区别就是,不会打印模式空间中的内容,也是立即退出;
20、r filename
读取指定文件的内容至当前文件被模式匹配到的行后面,合并文本输出;
21、R filename
从文件中读取一行追加,没调用一次这个命令,就会从文本中读入一行,从第一行一直往下读;
22、w filename
把模式空间中的内容保存至指定的文件中;如果文件不存在会自动创建,如果文件已经存在且有内容,会覆盖
其中的内容;
23、W filename
把当前模式空间的第一行内容覆盖写入指定文件中;这个命令是GNU扩展用法;
24、x
交换模式空间和保持空间中的内容;
25、s/regexp/replacement/[flags]
对模式空间中的内容做模式匹配,regexp部分可以用正则表达式语法,匹配到的内容将会被replacement部分
替换。
26、y/src/dst/
替换src部分指定的字符成目标dst指定的对应字符。src和dst部分不能用正则表达式;
是按字符替换;
27、#
指定注释;
28、=
打印当前输入行号,结尾会有一个换行符,也就是说行号与文本是分行显示的;
29、{cmd ; cmd ... }
将多个命令组合在一起;
30、v [version]
不做什么,如果因为GNU sed的扩展不支持,或者sed的版本不支持指定的用法,会让sed失败,
状态码为非正常的;
31、z
清空模式空间中的内容;内容清掉,变成一个空行(换行符还在);

3.3、sed的s命令特定说明

这里之所以把s命令单独作为一小节说明,一是重要,二是sed的形式变化多样;
语法结构为:
s/regexp/replacement/flags
其中regexp表示模式匹配部分;
replacement表示替换部分;
flags表示标记位;

s命令,通过regexp模式部分去匹配读入到模式空间中的行,如果匹配成功,指定模式空间中的部分会被替换成
replacement给定部分。
regexp部分可以使用正则表达式;
replacement部分不能使用正则表达式;
replacement可以为\n,其中n可以为1到9表示后向引用;
replacement可以为&,表示为前边模式匹配的部分;
查看替换,其分隔符(默认是/)可自行指定,常用的有s@regexp@replacement@,s#regexp#replacement#
对于GNU扩展的sed,在replacement部分支持以下部分:
\L 把replacement中的大写字母转换成小写字母,遇到\U和\E会改变或停止这种转换;  
\l  把接下来的一个字符转换成小写字母,如果是小写字母或者其他字符,保持不变;
\U  把replacement中的小写字母转换成大写字母,遇到\L和\E会改变或停止这种转换;
\u 把接下来的一个字符转换成大写字母,如果是大写字母或其他字符,保持不变;
\E  停止\L 和 \U的转换;(因为\L和\U的转换不止转换一个字符,所以可以利用\E来终止);

标志为可设置值:
g
对所有regexp模式匹配的内容都进行替换,如果不加上标志g,每一行只会替换一次(sed按行处理输入流,每一行
的处理,在sed中完成一次循环);

number
指定一个数字表示替换regexp模式匹配的第number处;

p
打印替换后模式空间中的内容;

w filename
将替换成功的结果保存至指定的文件中;

e
将替换后的部分作为shell命令,把shell命令执行结果输出到模式空间中来。

I 和 i
可以让regexp部分匹配的时候大小写不敏感,忽略大小写;

M和m
这个标记参数不懂,这里贴出原文:
The M modifier to regular-expression matching is a GNU sed extension which directs GNU sed 
to match the regular expression in multi-line mode. The modifier causes ^ and $ to match 
respectively (in addition to the normal behavior) the empty string after a newline, and the empty string 
before a newline. There are special character sequences (\` and \') which always match the beginning 
or the end of the buffer. In addition, the period character does not match a new-line character in 
multi-line mode.

3.4、使用频率很高的命令(带示例)

先准备一个文本,在shell接口执行:
[root@node2 ~]# cat >mytest1 < My name is wuxiaojie.
> Nice to meet you.
> Welcome to my work-house.
> EOF
[root@node2 ~]# cat mytest1 
My name is wuxiaojie.
Nice to meet you.
Welcome to my work-house.

#
注释部分;

例如:我显示文本第一行内容,可以标上一个注解
[root@node2 ~]# sed -n '1p#Dispalys the contents of the first line of the text' mytest1 
My name is wuxiaojie.

q [exit-code]
立即退出不在处理其他的命令和输入的文本;可以显式指定退出状态,0到255,如果大于边界,会重新计数;
比如:只打印文本的前两行,并理解退出,显式指明退出状态为253
[root@node2 ~]# sed  '2q 253' mytest1 
My name is wuxiaojie.
Nice to meet you.
[root@node2 ~]# echo $?
253
[root@node2 ~]# sed  '2q' mytest1 
My name is wuxiaojie.
Nice to meet you.
[root@node2 ~]# echo $?
0
[root@node2 ~]# sed  '2Q 253' mytest1 
My name is wuxiaojie.
这个示例顺便对比了指定退出状态值和不指定退出状态值以及命令q和命令Q的区别;
Q在指定要匹配到的行后,立即退出,而且连默认打印模式空间中的行为也省略了。

d
删除模式空间中的内容,立即开始下一个循环;
例如:删除文本第二行,其他行正常显示输出
[root@node2 ~]# sed '2d' mytest1 
My name is wuxiaojie.
Welcome to my work-house.
[root@node2 ~]# cat mytest1 
My name is wuxiaojie.
Nice to meet you.
Welcome to my work-house.

p 打印模式空间中的内容到标准输出,通常配合-n选项一起使用;
例如:只打印特定行,比如第2行
[root@node2 ~]# cat mytest1 
My name is wuxiaojie.
Nice to meet you.
Welcome to my work-house.
[root@node2 ~]# sed -n '2p' mytest1 
Nice to meet you.

n
把文本中的下一行覆盖写入模式空间中,这种行为会把sed处理文本指针指向了第二行,
也就是开始下一个循环的时候,会直接从第3行开始;(按照自己理解的组织的语言组织的,不一定准确)。
请看示例:
[root@node2 ~]# seq 6
1
2
3
4
5
6
[root@node2 ~]# seq 6|sed 'n;n;s/./T/'
1
2
T
4
5
T
实现的效果为,每隔三行,把数字替换成字母T。

{ commands}
命令组。里面的命令用分号隔开。把它们组织到{}内,这种用途可以显示,
对于单一地址或地址范围的行,用指定的不止单个sed命令来处理;

四、sed的地址概念

4.1、空地址(零地址)

根据前边sed的工作原理以及处理机制,我们知道,sed对输入流进行处理,我们可以选定值对输入流
中的部分行或多行进行处理,这个就是我们地址的作用,地址起到了定界的作用。如果省略地址,我们
可以理解为空地址,空地址通常表示对全文进行处理。

示例:
[root@node2 ~]# sed -n 'p' mytest1
My name is wuxiaojie.
Nice to meet you.
Welcome to my work-house.
[root@node2 ~]# wc -l mytest1
3 mytest1

利用简单的抑制模式空间的选项,配置p打印模式空间中内容到标准输出。
可以看到文本一共3行,结果也打印了三行,表示1,2,3行都被sed匹配到了,
而且被p命令处理。

4.2、单地址

单地址有两个形式:
number:指定一个特定的数字表示单个第number行;
/pattern/:被pattern模式所匹配的每一行;
如果边界字符/要用其他常见匹对字符替换,例如字符%,#等,可以写成如下形式:
\%pattern%,#pattern# 前边给非默认边界字符加上了一个转移符号,表示让sed识别成边界字符;
/pattern/I,\%regexp%I让模式匹配的时候,忽略字符大小写;

还有一种特殊的标记,符号美元符 $ 匹配文本最后一行;

示例:

[root@node2 ~]# sed -n '2p' mytest1 
Nice to meet you.
[root@node2 ~]# cat mytest1 
My name is wuxiaojie.
Nice to meet you.
Welcome to my work-house.
[root@node2 ~]# sed -n '/to/p' mytest1 
Nice to meet you.
Welcome to my work-house.

4.3、多地址,地址范围

addr1,addr2 表示匹配从地址addr1开始到地址addr2结束之间包括边界的所有的行,例如1,3表示前三行;
addr1,+N 表示匹配从地址addr1开始到地址(addr+N)结束之间包括边界的所有的行,例如3,+2表示
第3,第4和第5行;
addr1,~N:表示匹配从地址addr1开始到下一个地址编号是指定N的倍数的地址之间包括边界的所有的行,例如
3,~3表示从第3行开始,到第6行结束(6行是3行的倍数)
first~step:表示匹配从地址first开始,然后地址步进是step(即first+step)。例如:
1~2p表示奇数行,1,3,5,7,9,......
2~2p表示偶数行,2,4,6,8,10,......

number,/pattern/br/>其中/pattern/同样可以有以下形式:
\@pattern@,\#pattern#等等;
/pattern/I,\@pattern@I,#pattern#I

表示从第number行开始,到第一次被pattern模式所匹配到的行之间且包括边界的所有的行;

示例:

[root@node2 ~]# cat mytest1 
My name is wuxiaojie.
Nice to meet you.
Nice TO meet you.
Welcome to my work-house.
[root@node2 ~]# sed -n '1,/to/p' mytest1 
My name is wuxiaojie.
Nice to meet you.
[root@node2 ~]# sed -n '1,\/to/p' mytest1 
My name is wuxiaojie.
Nice to meet you.
[root@node2 ~]# sed -n '1,\@to@p' mytest1 
My name is wuxiaojie.
Nice to meet you.
[root@node2 ~]# sed -n '1,\@to@Ip' mytest1 
My name is wuxiaojie.
Nice to meet you.
[root@node2 ~]# sed -n '1,\@TO@p' mytest1 
My name is wuxiaojie.
Nice to meet you.
Nice TO meet you.
[root@node2 ~]# sed -n '1,\@TO@Ip' mytest1 
My name is wuxiaojie.
Nice to meet you.

/pattern1/,/pattern2/
表示被第一个模式匹配到的行到第二个模式匹配到的行之间且包括边界的所有的行;
同样可以使用其他边界字符已经让模式匹配部分忽略字符大小写,这里不再赘述;
示例:

[root@node2 ~]# cat mytest1 
My name is wuxiaojie.
Nice to meet you.
Nice TO meet you.
Welcome to my work-house.
[root@node2 ~]# sed -n '\&name&,/TO/p' mytest1 
My name is wuxiaojie.
Nice to meet you.
Nice TO meet you.
[root@node2 ~]# sed -n '\&name&,/TO/Ip' mytest1 
My name is wuxiaojie.
Nice to meet you.

四、sed的编辑命令

4.1、初级编辑命令(不涉及hold space)

d    Delete pattern space.  Start next cycle.
删除模式空间中的内容,开始下一个循环;

p    Print the current pattern space.
打印当前模式空间中的内容;

a \text  Append text, which has each embedded newline preceded by a backslash.
子啊行后面追加文本"text",追加的文本中可以使用\n实现多行追加;

i \test Insert text, which has each embedded newline preceded by a backslash.
在行前面插入文本"text",支持使用\n实现多行插入;

c \test Replace the selected lines with text, which has each embedded newline preceded by a backslash.
把匹配到的行替换为此处指定文本"text"

w filename   Write the current pattern space to filename.
保存模式空间匹配到的行至指定的文件中;

r filename  Append text read from filename.
读取指定文件的内容至当前文件被模式匹配到的行后面,实现文件内容合并;

=      Print the current line number.
为模式空间匹配到的行打印行号,行号是在对应行的上面另起一行;

!:条件取反
After  the  address (or address-range), and before the command, a !  may be inserted, which specifies that the command shall only be executed if the address (or address-range) does not match.

s/regexp/replacement/flags
Attempt  to  match  regexp  against  the  pattern  space.   If successful, replace that portion 
matched with replacement. The replacement may contain the special character & to refer to 
that portion  of  the  pattern space  which  matched,and  the  special  escapes \1 through \9 to refer
to the corresponding matching subexpressions in the regexp.and  the  special  escapes \1 through \9 to 
refer to the corresponding matching subexpressions in the regexp.
在上面的小节已经讲清楚了这种形式的详细用法。

示例:

示例1:d命令的简单应用
[root@node2 ~]# seq 9|sed -n '3d;2d;p'
1
4
5
6
7
8
9
[root@node2 ~]# seq 9|sed  '3d;2d'
1
4
5
6
7
8
9
删除了第3行和第2行;

示例2:a 命令的简单应用
[root@node2 ~]# seq 3|sed '2a \this is a test line\nhello,world'
1
2
this is a test line
hello,world
3
在第2行后面追加了两行文本;

示例3:i命令的简单应用
[root@node2 ~]# seq 3|sed '2i \this is a test line\nhello,world'
1
this is a test line
hello,world
2
3
在第2行插入了两行文本;

示例4:c 命令的简单应用
[root@node2 ~]# sed '/meet/Ic \replace' mytest1 
My name is wuxiaojie.
replace
replace
Welcome to my work-house.
[root@node2 ~]# cat mytest1 
My name is wuxiaojie.
Nice to meet you.
Nice TO meet you.
Welcome to my work-house.

把meet字符串匹配的行用replace文本替换;

示例5:w filename的简单应用
[root@node2 ~]# sed -ns '$w /tmp/userinfo' /etc/passwd /etc/group 
[root@node2 ~]# sed -ns '$p' /etc/passwd /etc/group
mysql:x:27:27:MariaDB Server:/var/lib/mysql:/sbin/nologin
mysql:x:27:
[root@node2 ~]# cat /tmp/userinfo 
mysql:x:27:27:MariaDB Server:/var/lib/mysql:/sbin/nologin
mysql:x:27:

这里的-s是表示命令行传入的多个文件作为不同的输入流处理,不合并;
取出/etc/passwd的最后一行和/etc/group的最后一行,并把它们写入
到一个新的文件中。(/tmp/userinfo)

示例5:r filename的简单应用

[root@node2 ~]# who|sed -n '2r /tmp/userinfop'
[root@node2 ~]# who|sed '2r /tmp/userinfo'
root     pts/0        2018-10-26 02:12 (aca86e01.ipt.aol.com)
root     pts/1        2018-10-26 02:12 (aca86e01.ipt.aol.com)
mysql:x:27:27:MariaDB Server:/var/lib/mysql:/sbin/nologin
mysql:x:27:
[root@node2 ~]# cat /tmp/userinfo 
mysql:x:27:27:MariaDB Server:/var/lib/mysql:/sbin/nologin
mysql:x:27:
[root@node2 ~]# who|sed '1r /tmp/userinfo'
root     pts/0        2018-10-26 02:12 (aca86e01.ipt.aol.com)
mysql:x:27:27:MariaDB Server:/var/lib/mysql:/sbin/nologin
mysql:x:27:
root     pts/1        2018-10-26 02:12 (aca86e01.ipt.aol.com)

示例6:=的简单应用
[root@node2 ~]# cat mytest1 
My name is wuxiaojie.
Nice to meet you.
Nice TO meet you.
Welcome to my work-house.
[root@node2 ~]# sed -n '2,4{=;p}' mytest1 
2
Nice to meet you.
3
Nice TO meet you.
4
Welcome to my work-house.
[root@node2 ~]# sed -n '2,4p' mytest1 
Nice to meet you.
Nice TO meet you.
Welcome to my work-house.

给第2,3,4行加上换行符

sed -n '$=' FILE
显示文本有多少行,只对最后一行进行换行符的添加,然后抑制模式空间中内容的输出

示例7:对命令取反
[root@node2 ~]# seq 5|sed -n '2d;p'
1
3
4
5
[root@node2 ~]# seq 5|sed -n '2!d;p'
2

4.2、高级编辑命令(可能涉及hold space)

h    Copy pattern space to hold space.
把模式空间中的内容覆盖写入保持空间中;

H    Copy pattern space to hold space.
把模式空间中的内容追加写入保持空间中;

g    Copy hold space to pattern space.
把保持空间中的内容覆盖至模式空间中;

G    Append hold space to pattern space.
把保持空间中的内容追加至默认空间中;

x    Exchange the contents of the hold and pattern spaces.
把模式空间中的内容与保持空间中的内容交换;

n    Read the next line of input into the pattern space.
覆盖匹配到的行的下一行至模式空间中;

N    Append the next line of input into the pattern space.  
追加读取匹配到的行的下一行至模式空间中;

d    Delete pattern space.  Start next cycle.
删除模式空间中的行;

D   If pattern space contains no newline, start a normal new cycle as if the d command was  issued. 
Otherwise, delete  text  in  the  pattern  space  up to the first newline, and restart cycle with  the resultant 
pattern space, without reading a new line of input.
删除多行模式空间中的所有行;

示例:(涉及到pattern space和hold space两个空间中的内容的处理,建议画图分解)

  • 显示文件的偶数行,大概形式如下
sed -n 'n;p' FILE

sed入门介绍_第3张图片

  • 显示奇数行
sed 'n;d' FILE

sed入门介绍_第4张图片

  • 实现tac简单的颠倒输出功能,大概形式如下:
sed '1!G;h;$!d'  FILE

sed入门介绍_第5张图片

  • 简单实现读取文件的最后一行,大概形式如下:
sed '$!d' FILE

这个判断逻辑很简单,我不画图说明,就是除了最后一行,每一轮循环读入模式空间中的内容
都被d命令删除了。最后一行,命令d不匹配,且没有抑制模式空间的输出,就会打印最后一行
的内容到标准输出。

  • 简单实现读取文件最后两行,大概形式如下:
sed '$!N;$;!D' FILE

sed入门介绍_第6张图片

  • 实现把原先文本中的空行全部删除,然后统一每一行之间加上空白行;
sed '/^$/d;G' FILE

这个很简单,/^$/匹配空白行,然后匹配到的行直接删掉;G是把保持空间中的内容追加至模式空间中,
因为保持空间中没有内容,所以作为空白行追加进了模式空间。

  • 给每一行的文本行后都添加一个空白行
sed 'G' FILE

这一题和上一题很像,除了没有先删除空白行之外。

五、sed的标签和分支用法

  • 定义标签语法
: label
       Label for b and t commands.

:label表示定义一个标签。通常标签名label以单个字符命名;比如:
:a表示定义一个标签或者定义一个分支a;
  • 跳转标签命令b

利用定义标签和标签跳转命令实现if else逻辑;
b label
Branch to label; if label is omitted, branch to end of script.
跳转到指定标签,如果标签省略了,直接跳转到sed的脚本结尾;

示例:

[root@node2 ~]# seq 9|sed '2~2bh;1~2ba;:a;s/$/ 奇数行/g;b;:h;s/$/ 偶数行/'
1 奇数行
2 偶数行
3 奇数行
4 偶数行
5 奇数行
6 偶数行
7 奇数行
8 偶数行
9 奇数行

定义了两个标签,一个是a,一个是h;
标签a后边部分是给奇数行后边加上"空格奇数行",而h标签后边部分是给偶数行后边加上"空格偶数行";
  • t tabel
    If a s/// has done a successful substitution since the last input line was read and since the last t or T
    command, then branch to label; if label is omitted, branch to end of script.
    t和下面要讲到的T,对比于b的作用略有不同,它们三个都可以用来做标签之间的跳转,b是无条件的跳转,
    t和T是有条件的跳转。t tabel ,当s///子串替换成功的时候,会使用t来做跳转;

  • T tabel
    If no s/// has done a successful substitution since the last input line was read and since the last t or T
    command, then branch to label; if label is omitted, branch to end of script. This is a GNU extension.
    当s///子串替换失败的时候,会使用T来做跳转。

t和T命令的示例:
示例摘抄地址:http://blog.chinaunix.net/uid-639516-id-2692525.html

[root@node2 ~]# cat txt
AA
BC
AA
CB
CC
AA
[root@node2 ~]# sed '/^AA/s/$/ YES/;T;s/$/ NO/' txt 
AA YES NO
BC
AA YES NO
CB
CC
AA YES NO
[root@node2 ~]# sed '/^AA/s/$/ YES/;t;s/$/ NO/' txt 
AA YES
BC NO
AA YES
CB NO
CC NO
AA YES

使用T命令的案例,表示对以AA开头的行,后边加上YES和NO,中间有空格;
使用t命令的案例,表示对AA开头的行行尾加上YES,非AA开头的行行尾加上NO,中间要有空格。

感谢和参考:
sed的GNU官网:
http://www.gnu.org/software/sed/

在线手册:
http://www.gnu.org/software/sed/manual/

其他在线文档以及FAQ:
http://sed.sourceforge.net/#docs

参考优秀的互联网博文:
https://blog.csdn.net/yanquan345/article/details/19613443
https://www.cnblogs.com/theCambrian/p/3606214.html

https://blog.csdn.net/bit_clearoff/article/details/70471522
https://blog.csdn.net/huangjin0507/article/details/51274135

转载于:https://blog.51cto.com/9657273/2309580

你可能感兴趣的:(操作系统,数据库,shell)