sed命令总结-Linux

sed命令总结-Linux

linuxsed

2018年02月08日 19时27分57秒


命令语法经常忘记,每次总是看笔记不切实际,记不起来的要多查manual,本次总结按照manual总结,希望下次的你在使用man手册的时候能记起来这些例子。
sed流处理,每次只会取文本的一行到模式空间(pattern space)中进行处理,处理完成之后默认输出模式空间的内容。再次取下一行内容的时候会将模式空间的内容替换掉,如果需要模式空间中存在多行内容需要保持空间(hold space)的配合。

sed基础部分

sed的语法格式

SYNOPSIS(概要)中描述了sed的使用格式
sed [OPTION]... {script-only-if-no-other-script} [input-file]...

(1) OPTION:sed命令的选项,辅助操作方便的,不是真正的定义处理文件命令的地方


-n, --quiet, --silent suppress automatic printing of pattern space 限制sed命令不自动输出模式空间的内容。每次sed取一行数据放到模式空间(模式空间在sed高级部分会再说明)进行处理,处理完之后会将模式空间的内容自动输出,在有些时候我们需要更加灵活的定义sed输出的内容,故需要限制原本sed的默认输出,转而使用script中指定p(即是print)命令来指定输出。 -e script, --expression=script add the script to the commands to be executed 默认情况下sed是只能指定一条处理命令在script中(目前版本的sed我没有加-e选项也不会报错),如果需要指定多条处理命令需要加上-e选项,然后对script中指定的多条命令使用分号隔开。 -f script-file, --file=script-file add the contents of script-file to the commands to be executed 不直接使用script中指定的命令,而是从文件中读取处理的命令,文件中可以指定多个命令,每一个命令放在单独的一行上,不需要使用分号结尾。 ![Diagram](./attachments/1551876130958.drawio.html) -r, --regexp-extended use extended regular expressions in the script. 在script中使用正则的时候默认是标准正则,如果需要识别扩展正则表达式,需要指定-r选项。

(2) script-only-if-no-other-script:指定处理文件的命令的地方,指定了应用于流数据上的单个命令(后面使用script指代这一部分),需要使用单引号包裹
(3) input-file:待处理的文件,如果最后不加待处理文件,sed编辑器会指定命令输入到STDIN标准输入上

sed编辑器基础

下面的内容分析一下script的基础使用部分,大约分为六个部分,对应着

替换(s)

基础语法

	s/regexp/replacement/
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 sub-expressions in the regexp. 上面的是替换命令的基础语法,表示在sed会判断读取到pattern space(模式空间)的数据行是否能够匹配到regexp,如果能够匹配会将匹配到的部分使用replacement替换,但是默认只会替换每行中匹配的第一处,如果行中出现第二处匹配,则不会在进行替换。故存在一下语法:
s/regexp/replacement/flags flags为替换标记:
数字(1-9):表示将替换匹配到的**第几处**地方
g:表示会替换所有匹配的文本
p:表示打印匹配regexp并替换处理之后的数据
w file:将替换的结果写入到文件中去
上面还提到了&与\1到\9的模式替代,最后再说。

基础语法示例

# 默认只会替换出现的第一处
[root@localhost ~]# echo "one one one" | sed -n 's/one/two/p'
two one one
# 使用gp参数,禁止sed默认输出
[root@localhost ~]# echo "one one one" | sed -n 's/one/two/gp'
two two two
# 使用数字与p参数替换每行出现的第二处匹配,禁止默认输出
[root@localhost ~]# echo "one one one" | sed -n 's/one/two/2p'
one two one
# 对两行内容进行处理,如果不禁止sed的默认输出,可以看出partten没有匹配到的也会被输出,所以可以看出flags的输出标记与sed的默认输出的是存在差别的
[root@localhost ~]# echo -e "one one\ntwo two" | sed 's/one/two/'
two one
two two
[root@localhost ~]# echo -e "one one\ntwo two" | sed -n 's/one/two/p'
two one

使用寻址

默认情况下是所有的数据行都会进入模式空间被处理的,当我们要处理特定行的时候,就需要使用sed提供的Addresses了。在未指定处理的行虽然也会读取到模式空间,却并不会被处理。
需要注意的是,寻址可以运用于任何一个单字命令或命令组合之前,用来指定那些行被处理

Addresses
Sed commands can be given with no addresses, in which case the command will be executed for all input lines; with one
address, in which case the command will only be executed for input lines which match that address; or with two addresses, in
which case the command will be executed for all input lines which match the inclusive range of lines starting from the first
address and continuing to the second address. Three things to note about address ranges: the syntax is addr1,addr2 (i.e.,
the addresses are separated by a comma); the line which addr1 matched will always be accepted, even if addr2 selects an ear-
lier line; and if addr2 is a regexp, it will not be tested against the line that addr1 matched. 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. The following address types are supported: number Match only the specified line number. first~step
Match every step’th line starting with line first. For example, ‘‘sed -n 1~2p’’ will print all the odd-numbered
lines in the input stream, and the address 2~5 will match every fifth line, starting with the second. first can be
zero; in this case, sed operates as if it were equal to step. (This is an extension.) 1、循环的方式first为第一次处理的行,step为步长为多少,如上面的2~5的例子,第一个处理的是第2行,第二个则为第7行。 $ Match the last line. 2、$只会匹配最后一行 /regexp/
Match lines matching the regular expression regexp. 3、使用文本过滤的方式,如果该行中存在匹配,才会执行后面的单命令操作。 \cregexpc
Match lines matching the regular expression regexp. The c may be any character. 4、因为有些情况下一直使用/进行对正则表达式包裹可能存在歧义,故提供指定任意字符包裹正则的语法,开始使用\进行转义该字符,结尾处不需要使用\转义 GNU sed also supports some special 2-address forms:
下面的三种都是数字寻址方式:都是闭区间 0,addr2
Start out in "matched first address" state, until addr2 is found. This is similar to 1,addr2, except that if addr2
matches the very first line of input the 0,addr2 form will be at the end of its range, whereas the 1,addr2 form will
still be at the beginning of its range. This works only when addr2 is a regular expression. 5、从0开始的行开始,知道处理到第addr2行 addr1,+N
Will match addr1 and the N lines following addr1. 6、从第addr1开始处理其与后N行数据 addr1,~N
Will match addr1 and the lines following addr1 until the next line whose input line number is a multiple of N. 7、从第addr1开始处理到第N行

寻址练习

# 文件内容
[root@localhost ~]# cat file
this is a test line one
this is a test line two
this is a test line three
this is a test line four
this is a test line five
# 寻址方式1:从1开始,循环步长为2
[root@localhost ~]# sed -n '1~2p' file
this is a test line one
this is a test line three
this is a test line five
# 寻址方式2:输出最后一行
[root@localhost ~]# sed -n '$p' file
this is a test line five
# 寻址方式3:正则匹配定位行
[root@localhost ~]# sed -n '/three/p' file
this is a test line three
# 寻址方式4:指定包裹正则的字符
[root@localhost ~]# sed -n '\!three!p' file
this is a test line three
# 寻址方式5:从第1行开始,到第3行输出
[root@localhost ~]# sed -n '1,3p' file
this is a test line one
this is a test line two
this is a test line three
# 寻址方式6:从第一行开始,包括第一行,输出其自身在内以及其后一行
[root@localhost ~]# sed -n '1,+1p' file
this is a test line one
this is a test line two
# 寻址方式7:同寻址方式5
[root@localhost ~]# sed -n '1,~3p' file
this is a test line one
this is a test line two
this is a test line three

命令组合与练习

先来看一下我们为什么需要命令组合

# 我们想要对文本的第1到3行的this替换为that,line替换为text,如果每一个单字命令之前不写上寻址是不能保证每一个命令都作用与1到3行的。
[root@localhost ~]# sed '1,3s/this/that/g; s/line/text/g' file
that is a test text one
that is a test text two
that is a test text three
this is a test text four
this is a test text five

这个时候需要用到命令组合了,看一下官方的解释

{      Begin a block of commands (end with a }).
} The closing bracket of a { } block.
解释的很简单,其实用起来也是那么简单,如果想要对一个寻址到行执行多个单字命令,使用大括号将他们括起来就行了。 # 看示例(非常简单-_-):
[root@localhost ~]# sed '1,~3{s/this/that/g; s/line/text/g}' file
that is a test text one
that is a test text two
that is a test text three
this is a test line four
this is a test line five
# 该示例完成之后接着来单字命令

删除(d)

前面将替换与寻址看完,在看删除其实也是非常的简单的,不过删除存在两种,目前先介绍d(delete),D留到进阶。

d      Delete pattern space.  Start next cycle.
将模式空间的数据删除掉,并读取下一行的内容,这个删除是非常的干净的,此时输出模式空间什么也没有。 # 删除练习 # 删除第1到3行
[root@localhost ~]# sed -n '1,3D; p' file
this is a test line four
this is a test line five
# 这儿的模式匹配使用了两个,使用逗号隔开,one打开了删除,three为删除的关闭
[root@localhost ~]# sed '/one/,/three/D' file
this is a test line four
this is a test line five

插入与附加(i、a)

既然可以删除,那定然是可以插入与附加文本的,插入是i(insert),附加是a(append)

(1)i插入命令会在指定行之前增加一个新行
(2)a追加命令会在指定行之后增加一个新行

命令格式:

# 首先看一下manual

       i \

       text   Insert text, which has each embedded newline preceded by a backslash.
a \ text Append text, which has each embedded newline preceded by a backslash. # 总结使用方法如下
sed '[address]command\new line'
# 如上address是指定的行地址,地址可以指定,也可以不指定,如果不指定都会在数据流之前与之后插入与追加。地址指定可以使用数字行号或文本模式,但是不能指定区间! # 例子如下: # 在第三行之前插入一行。
[root@localhost ~]# sed '3i\this is a insert line' file
this is a test line one
this is a test line two
this is a insert line
this is a test line three
this is a test line four
this is a test line five
# 在第三行之后追加一行。
[root@localhost ~]# sed '3a\this is a append line' file
this is a test line one
this is a test line two
this is a test line three
this is a append line
this is a test line four
this is a test line five
# 在第三行之后追加多行,在命令行追加或插入,必须对每一行用反斜线换行。
[root@localhost ~]# sed '3a\this is a append line 1\
> this is a append line 2' file
this is a test line one
this is a test line two
this is a test line three
this is a append line 1
this is a append line 2
this is a test line four
this is a test line five

修改(c)

修改行c(change)的使用方法与插入、追加使用方法一样,单独拿出来的原因就是有一点,修改行可以使用地址区间,但是会将地址区间的全部内容整体替换为待替换内容。

先看一下manual
c \ text Replace the selected lines with text, which has each embedded newline preceded by a backslash.
替换寻址到的文本,需要嵌入的新行放在反斜杠之后。 # 例子
[root@localhost ~]# sed '3c\this is a change line' file
this is a test line one
this is a test line two
this is a change line
this is a test line four
this is a test line five

转换(y)

       y/source/dest/
Transliterate the characters in the pattern space which appear in source to the corresponding character in dest. 转换命令(transform)会将寻址到行中可以匹配source中的单个字符的字符全部转换为对应dest中的字符,source与dest相当于是一个map映射关系。 # 例
[root@localhost ~]# echo "123456" | sed -n 'y/123/456/; p'
456456

打印(p、=、l)

p用来打印文本行,P在进阶中会有
=用来打印行的行号
l(小写的l)用来打印行的内容,会将不可显示的字符使用ASCII打印

       p      Print the current pattern space.

       =      Print the current line number.

       l      List out the current line in a ‘‘visually unambiguous’’ form.

       l width
List out the current line in a ‘‘visually unambiguous’’ form, breaking it at width characters. This is a GNU exten-
sion.
这个与不加width会多出一个按照width指定的字符个数进行切词,详细切词后看本节最后一个例子 # 例
[root@localhost ~]# echo -e "one\ntwo" | sed -n '$p'
two
[root@localhost ~]# echo -e "one\ntwo" | sed -n '=; p'
1
one
2
two
[root@localhost ~]# echo -e "one\ttwo" | sed -n 'l'
one\ttwo$
[root@localhost ~]# echo -e "one\ntwo" | sed -n 'l'
one$
two$
[root@localhost ~]# echo -e "one\ntwo" | sed -n 'p; l 2'
one
o\
n\
e$
two
t\
w\
o$

处理文件(r、w)

       r filename
Append text read from filename.
读取文件中的数据并追加在指定行之后,实际就是将a单字符命令的指定new line内容从filename对应的文件中读取,filename可以使用相对路径或绝对路径,但是对文件要有读权限,且地址区间如a单字符命令一样是不能指定区间的。
使用格式:
[address]r filename w filename
Write the current pattern space to filename.
对模式空间中的行判断寻址是否匹配,如果匹配将内容输出到文件,filename同r单字符命令
使用格式:
[address]w filename # 例:
[root@localhost ~]# cat file
this is a test line one
this is a test line two
[root@localhost ~]# cat file1
this file1 content
[root@localhost ~]# sed '1r file1' file
this is a test line one
this file1 content
this is a test line two
[root@localhost ~]# sed '1,2w file2' file
this is a test line one
this is a test line two
[root@localhost ~]# cat file2
this is a test line one
this is a test line two

sed进阶

在后面进行之前先了解两个概念pattern space与hold space

模式空间&保持空间

pattern space:模式空间,容纳当前输入行的缓冲区,在sed基础中我们接触到的都是每次读取一行入模式空间,后面便会接触到模式空间存在多行内容的情况。
hold space:保持空间,作为一个辅助的缓冲区,可以和模式空间进行交互(交互通过单字命令进行),但是命令是不能直接作用于保持空间的。

sed在正常情况下,将处理的行读入模式空间,脚本中的script就一条一条的执行,直到执行完毕。然后该行被输出,模式被清空。接着重复上面的动作,直到文件被处理完毕。

多行命令

为什么需要多行命令?

前面提到的命令中每次都是读取文件中的一行到模式空间,模式空间也只会存在一行数据,这种情况下我们每次只能对一行数据进行寻址与匹配。就像下面这样。

一个文件中的内容如下:
this is a test line one
this is a test line two
this is a test line three
this is a test line four
this is a test line five
现在我们要查找one two两个词,但是这两个词可能存在两行中,如果普通的sed命令是不能匹配到两个单词的,针对于这种情况sed提供了多行命令来针对多行操作,将多行数据读入模式空间组成一个多行组,针对多行组操作便可解决上面的问题。

什么是多行组?

多行组:将文本中的多行数据读入模式空间,单行命令此时对模式空间操作,从外面将此时模式空间看作一行(宏观上);而多行命令对模式空间进行操作,是针对于模式空间内部操作的,将模式空间内的数据看成单独的行,每行之间还是通过\n进行分割。

下面来逐个分析manual中剩余的命令

进阶命令

next命令(n、N)

n N    Read/append the next line of input into the pattern space.
小写的n(单行命令)将下一行读入模式空间,且不会跳转到命令的最初重新对数据行执行所有的命令
大写的N(多行命令)将下一行追加到模式空间,与当前行组成一个多行组,多行组内,文本行之间仍然是通过\n进行分割 # 将当前寻址定位到的
[root@localhost ~]# cat file
this is a test line one
this is a test line two
this is a test line three
this is a test line four
this is a test line five

下面来分析一下n与N的区别:

1、n命令实例与总结


[root@localhost ~]# sed '{n; s/this is a test line//g; p}' file
this is a test line one
two
two
this is a test line three
four
four
this is a test line five
[root@localhost ~]# sed -n '{n; s/this is a test line//g; p}' file
two
four

通过上面分析可得
(1) 读到第一行的时候出发n将下一行读入模式空间,使用sed的默认输出会将第一行输出,并对后面读入的数据进行执行剩余命令
(2) 第二行已经被读入模式空间过,故该行不会在出发n命令,但是会执行n之后的剩余命令
(3) 第三行之后重复上面的步骤
(4) n在将下一行读取之后,指针还是停留在第一行

2、N命令示例与总结

[root@localhost ~]# sed -n '{N; s/this is a test line//1; p}' file
one
this is a test line two
three
this is a test line four
[root@localhost ~]# sed -n '{N; s/this is a test line//2; p}' file
this is a test line one
two
this is a test line three
four
[root@localhost ~]# sed '{N; s/this is a test line//g; p}' file
one
two
one
two
three
four
three
four
this is a test line five
[root@localhost ~]# sed '{N; s/this is a test line//1; p}' file
one
this is a test line two
one
this is a test line two
three
this is a test line four
three
this is a test line four
this is a test line five

通过上面分析可得
(1) 读取第一行之后出发N命令,将第二行追加到模式空间,将模式空间的两行看成一行进行操作,p单字命令最后输出模式空间,sed默认再输出模式空间
(2) N命令将下一行追加到模式空间之后,指针会移动到下一行,如上面将第二行追加到模式空间之后会将指针移动到第二行,故下次在读取就是第三行了

n与N有一个共同点就是:在没有下一行供n或N进行触发的时候,不会对这一行数据执行n、N命令

多行删除命令(D)

       D      Delete  up  to the first embedded newline in the pattern space.  Start next cycle, but skip reading from the input if there is still data in the pattern space.
D会删除模式空间的第一行,该命令会删除到换行符含换行符在内的所有字符
# 例子如下:
[root@localhost ~]# cat file1 first line last line
# 假设我们要删除紧挨first行前的空白行与后的空白行
[root@localhost ~]# sed -n '/^$/{N; /first/D}; /first/{p; n; d}; p' file1
first line last line

单行d与多行D总结

单行d:删除指定行之后的空行(先找到指定行,在删除之后的空白行)

多行D:删除目标行之前的行,匹配要删除的行,将后面的一行匹配加入模式空间,然后删除第一行。需要非常注意的是D命令有一个非常强大的地方(只有D命令存在该情况)就是 :D命令会强制sed返回脚本的起始处,对同一模式空间的内容重新执行这些命令(不会读取新的文本行),命令行中加入N就能循环扫过这个模式空间

多行打印命令(P)

P      Print up to the first embedded newline of the current pattern space.
打印模式空间中的第一行 [root@localhost ~]# cat file1
first line
last line
[root@localhost ~]# sed -n 'N; p' file1
first line
last line
[root@localhost ~]# sed -n 'N; P' file1
first line

排除命令(!)

! 感叹号命令用来排除(negate),让寻址匹配到的命令不起作用。

[root@localhost ~]# cat file1
first line
secod line
third line
last line
[root@localhost ~]# sed -n 'N; /first/!P' file1
third line

模式空间与保持空间操作命令(h、H、g、G、x)

       h H    Copy/append pattern space to hold space.

       g G    Copy/append hold space to pattern space.

       x      Exchange the contents of the hold and pattern spaces.

下面来两个例子,练习熟悉一下模式空间的操作
1、模式空间之间的复制与追加

[root@localhost ~]# cat file
this is a test line one
this is a test line two
this is a test line three
this is a test line four
this is a test line five
[root@localhost ~]# sed -n '/two/{h; p; n; p; g; p}' file
this is a test line two
this is a test line three
this is a test line two [root@localhost ~]# sed -n '/two/{h; p; n; H; p; n; p; x; p}' file
this is a test line two
this is a test line three
this is a test line four
this is a test line two
this is a test line three

2、文本行反转

[root@localhost ~]# cat file
this is a test line one
this is a test line two
this is a test line three
this is a test line four
this is a test line five
[root@localhost ~]# sed -n '{1!G; h; $p}' file
this is a test line five
this is a test line four
this is a test line three
this is a test line two
this is a test line one
[root@localhost ~]# sed '{1!G; h; $!d}' file
this is a test line five
this is a test line four
this is a test line three
this is a test line two
this is a test line one

改变流(:、b、t、T)

       b label
Branch to label; if label is omitted, branch to end of script.
[address]b lable
address决定了那些行的数据会触发分支命令,lable指定了要跳转的位置,如果没有加lable参数,跳转命令会直接跳转到script的结尾 : label
Label for b and t commands.
标签以:开始,最多可以是7个字符长度,放在b或者t、T命令之后会进行跳转到script的指定位置。 t label
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. 测试命令也是类似分支命令,不过测试命令是根据替换的结果进行跳转,如果替换命令成功匹配并替换了一个模式则会跳转指定标签,否则不跳转。
[address]t lable
这儿的address是替换命令,类是b命令,lable指定了要跳转的位置,如果没有加lable参数,跳转命令会直接跳转到script的结尾 T label
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. 测试失败流,除了是替换失败才会跳转,其余与t命令相同

下面来几个例子

# 第一个b跳转的时候是需要在b的前面判断一下的,不然就无限循环了
[root@localhost ~]# echo "this,is,a,test." | sed -n '{
> : start
> s/,/ /1p
> /,/b start}'
this is,a,test.
this is a,test.
this is a test. # 而使用t跳转的时候是不用担心这个情况的
[root@localhost ~]# echo "this,is,a,test." | sed -n '{
> : start
> s/,/ /1p
> t start}'
this is,a,test.
this is a,test.
this is a test. # 测试错误流
[root@localhost ~]# echo "this,is,a,test." | sed -n '{
> : success
> s/inexistence//
> T error
> a\replace fail
> : error
> s/,/ /1p
> t success}'
this is,a,test.
this is a,test.
this is a test.

模式替代(&、\1-\9)

模式替代是s单字符替换命令的一种扩展,先看看s命令中的描述与什么情况下需要使用模式替换。

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 sub-expressions in the regexp.

如下:如若让cat与hat都加上双引号,模式替换中如果一个单词一个单词的替换是可以,但是如果使用通配符进行匹配是不行的,不过加上模式替换就比较简单了

[root@localhost ~]# echo "The cat sleeps in his hat" | sed 's/cat/"cat"/g[root@localhost ~]# echo "The cat sleeps in his hat" | sed 's/.at/"&"/g'
The "cat" sleeps in his "hat"'
The "cat" sleeps in his hat

&符号

&可以用来代表替换命令中匹配的模式,不管模式匹配的是什么样子的文本,都可以在替换模式中使用&来代替被匹配的到的内容。

[root@localhost ~]# echo "The cat sleeps in his hat" | sed 's/.at/"&"/g'
The "cat" sleeps in his "hat"

子模式

sed编辑器使用圆括号来定义一个子模式,然后使用\1~\9来表明子模式的位置,第一个子模式使用\1表示,依次类推。在替换模式中使用圆括号时,必须使用转义字符将他们标记为分组字符,而不是普通的圆括号。

来两个例子:

# 替换cat hat之间的字符串为in this
[root@localhost ~]# echo "The cat sleeps in his hat" | sed 's/\(cat\).*\(hat\)/\1 in this \2/'
The cat in this hat # 在子模式之间插入文本
[root@localhost ~]# echo "123456789" | sed '{
> : start
> s/\(.*[0-9]\)\([0-9]\{3\}\)/\1,\2/
> t start
> }'
123,456,789

退出sed(q、Q)

       q [exit-code]
Immediately quit the sed script without processing any more input, except that if auto-print is not disabled the current pattern space will be printed. The exit code argument is a GNU extension.
退出之前会打印模式空间的内容
Q [exit-code]
Immediately quit the sed script without processing any more input. This is a GNU extension.
直接退出 # 显示数据后十行
[root@localhost ~]# sed '{
> : start
> $q; N; 11,$D
> b start
> }' file
7
8
9
10
11
12
13
14
15
16
# 在识别最后一行的时候退出,模式空间识别是否存在十行数据,如果不多于十行就一直向模式空间添加数据,如果多余十行,判断是否到达最后一行,如果没有到达最后一行,就继续向模式空间添加数据,同时删除第一行(D会删除模式空间的第一行并回到命令的开始)
上一篇:修改Excel


下一篇:python连接mysql获取表信息(表名、字段数、字段空值率)