前言

强忍着不适,把实验做完,这个东西好用是好用,就是正则表达式让人头晕目眩。它的这个替换算法和vi的查找替换看起来貌似一样的。

sed是贝尔实验室的Lee E. McMahon在1973年到1974年开发的流编辑器,sed是基于交互式行编辑器ed开发的软件,sed与ed一样也是行处理编辑器,在sed中搞清楚你需要编辑的是哪一行内容很重要,同时sed是最早开始支持正则表达式的工具之一。我们可以使用sed非常轻松地完成非交互式的文件编辑工作,包括但不限于对文件的增、删、改、查等操作。

一 sed基本指令

        sed基本指令sed会逐行扫描输入的数据,并将读取的数据内容复制到缓冲区中,我们称之为模式空间,然后拿模式空间中的数据与给定的条件进行匹配,如果匹配成功则执行特定的sed指令,否则sed会跳过输入的数据行,继续读取后续的数据。默认情况下sed会把最终的数据结果通过标准输出显示在屏幕上。sed数据处理流程如下图所示。

sed的帮助信息如下所示:

用法: sed [选项]... {脚本(如果没有其他脚本)} [输入文件]...

-n, --quiet, --silent
                 取消自动打印模式空间
  -e 脚本, --expression=脚本
                 添加“脚本”到程序的运行列表
  -f 脚本文件, --file=脚本文件
                 添加“脚本文件”到程序的运行列表
  --follow-symlinks
                 直接修改文件时跟随软链接
  -i[SUFFIX], --in-place[=SUFFIX]
                 edit files in place (makes backup if SUFFIX supplied)
  -l N, --line-length=N
                 指定“l”命令的换行期望长度
  --posix
                 关闭所有 GNU 扩展
  -r, --regexp-extended
                 在脚本中使用扩展正则表达式
  -s, --separate
                 将输入文件视为各个独立的文件而不是一个长的连续输入
  -u, --unbuffered
                 从输入文件读取最少的数据,更频繁的刷新输出
  -z, --null-data
                 separate lines by NUL characters
      --help     打印帮助并退出
      --version  输出版本信息并退出

sed常用的命令选项

sed基本操作指令

sed指令执行前需要先根据条件定位需要处理的数据行,如果没有指定定位条件,则默认sed会对所有数据行执行特定的指令。sed支持的数据定位方法如下表所示。

二 通过实例学习

下面我们通过案例练习来说明前面三个表格中的每个概念。sed是逐行处理软件,我们可能仅输入了一条sed指令,但系统会将该指令应用在所有匹配的数据行上,因此相同的指令会被反复执行N次,这取决于匹配到的数据有几行。

首先创建一个测试文件,在启动输入几行测试数据touch 1.txt,并输入经过审核和严谨思考的的测试数据:

hello world
are you ok

文件显示实例

sed 'p' 1.txt

经过测试sed p 1.txt和sed 'p' 1.txt的效果是相同的,p两边不加单引号也可以吗?这个还需要更多的验证。

root@ubuntu:~# sed p 1.txt
hello world
hello world
are you ok
are you ok
root@ubuntu:~#

当没有指定条件时,默认会匹配所有的数据行,因此test.txt文件有多少行p指令就被执行多少次,sed读取文件的第1行执行p指令将该行内容显示在屏幕上,接着读取文件的第2行继续执行p指令再将该行内容显示在屏幕上。但是,为什么最终每个数据行却打印显示了两次呢?因为哪怕没有p指令,sed也会默认将读取到的所有数据行显示在屏幕上,所以p指令数据行被打印显示了一次,接着sed默认又将读取的数据行再显示了一次,最终每行显示了两次。可以使用-n选项屏蔽sed默认的输出功能。关闭默认的输出功能后,所有的数据行将仅显示一次。如下所示:

root@ubuntu:~# sed -n p 1.txt
hello world
are you ok
root@ubuntu:~#

指定显示文件的某一行,p前加行号,例如显示第二行sed -n 2p 1.txt

root@ubuntu:~# sed -n 2p 1.txt
are you ok
root@ubuntu:~#

sed支持管道作为输入源,如下所示,显示管道中数据的第一行。

root@ubuntu:~# cat 1.txt | sed -n 1p
hello world
root@ubuntu:~#

上面的命令当没有指定任何匹配条件时,sed将匹配所有的数据行。但是,sed也支持多种方式定位特定的数据行,直接写行号就是最直接的一种方式,其他如正则表达式等方式也很实用。满足条件的行才会执行sed指令,否则不做任何操作,sed继续读取文件下一行内容,直到文件结尾程序退出。

为了让测试实例更加丰满,创建新的测试文件touch 2.txt,输入下面的内容:

hello world
are you ok
who are you
xixi I'm a baby
What are you doing
There is a mm in the box

显示2.txt 的2-5行。并且输出行号,如下所示:3.txt是一个中间文件,实际上就是带行号的2.txt。cat -n 2.txt > 3.txt | sed -n '2,5p' 3.txt

root@ubuntu:~# cat -n 2.txt > 3.txt | sed -n '2,5p' 3.txt2  are you ok3  who are you4  xixi I'm a baby5  What are you doing
root@ubuntu:~#

指定显示任意行,且是多个,多个行指令之间使用分号分隔。例如:显示1,3,5行,sed -n 1p;3p;6p,如下所示:

root@ubuntu:~# cat -n 2.txt > 3.txt & sed -n '1p;3p;6p' 3.txt1  hello world3  who are you6  There is a mm in the box
root@ubuntu:~#

p指令的美院符号"$"也表示最后一行。显示3到最后一行如下所示:cat -n 2.txt > 3.txt | sed -n '3,$p' 3.txt,

root@ubuntu:~# cat -n 2.txt > 3.txt | sed -n '3,$p' 3.txt3  who are you4  xixi I'm a baby5  What are you doing6  There is a mm in the box
root@ubuntu:~#

显示第2行,及后面的2行:cat -n 2.txt > 3.txt | sed -n '2,+2p' 3.txt,共显示三行。

root@ubuntu:~# cat -n 2.txt > 3.txt | sed -n '2,+2p' 3.txt2  are you ok3  who are you4  xixi I'm a baby
root@ubuntu:~#

显示1,3,5 ...奇数行,步长为2,cat -n 2.txt > 3.txt | sed -n '1~2p' 3.txt

root@ubuntu:~# cat -n 2.txt > 3.txt | sed -n '1~2p' 3.txt1  hello world3  who are you5  What are you doing
root@ubuntu:~#

显示2、4、6 ...偶数行,步长为2,cat -n 2.txt > 3.txt & cat 3.txt | sed -n '2~2p'

root@ubuntu:~# cat -n 2.txt > 3.txt & cat 3.txt | sed -n '2~2p'
[1] 270802  are you ok4  xixi I'm a baby6  There is a mm in the box
[1]+  已完成               cat -n 2.txt > 3.txt
root@ubuntu:~#

显示最后一行:cat 2.txt | sed -n '$p'

root@ubuntu:~# cat 2.txt | sed -n '$p'
There is a mm in the box
root@ubuntu:~#

显示包含mm的行:mm是薛定谔的猫,并不是其他的意思,没错,是猫咪。sed -n '/mm/p' 2.txt

root@ubuntu:~# sed -n '/mm/p' 2.txt
There is a mm in the box
root@ubuntu:~#

显示文件2.txt包含are的行,并显示行号:cat -n 2.txt > 3.txt | sed -n '/are/p' 3.txt

root@ubuntu:~# cat -n 2.txt > 3.txt | sed -n '/are/p' 3.txt2  are you ok3  who are you5  What are you doing
root@ubuntu:~#

除了直接使用行号,sed还支持使用正则表达式定位特定的数据行。上面这条命令会读取文件的第1行,使用正则表达式匹配是否包含are,如果包含are则执行p指令,否则不执行任何操作,sed继续读取下一行数据,重复按照条件匹配数据行直到读取文件结束。上面的结果说明2.txt文件中的第2、3、5行都包含are,其他所有行都没有包含are字符串。

匹配以ok结尾的行并显示:cat -n 2.txt > 3.txt | sed -n '/ok$/p' 3.txt

root@ubuntu:~# cat -n 2.txt > 3.txt | sed -n '/ok$/p' 3.txt2  are you ok
root@ubuntu:~#

下面这条命令可以匹配字母y开头,以u结尾,中间包含任意1个字符的数据行,最后使用p指令将匹配的数据行显示在屏幕上。cat -n 2.txt > 3.txt | sed -n '/y.u/p' 3.txt

root@ubuntu:~# cat -n 2.txt > 3.txt | sed -n '/y.u/p' 3.txt2  are you ok3  who are you5  What are you doing
root@ubuntu:~#

下面这条命令可以匹配字母d开头,以g结尾,中间包含任意3个字符的数据行,最后使用p指令将匹配的数据行显示在屏幕上。cat -n 2.txt > 3.txt | sed -n '/d...g/p' 3.txt

root@ubuntu:~# cat -n 2.txt > 3.txt | sed -n '/d...g/p' 3.txt5  What are you doing
root@ubuntu:~#

为了配合测试,新建一个测试文件touch 4.txt,并输入如下内容:

root@ubuntu:~# cat 4.txt
hello world
are you ok
who are you 1234
xixi I'm a baby 5678
What are you doing 90
There is a mm in the box
root@ubuntu:~#

匹配包含数字的行,并给他们排行号:sed -n '/[0-9]/p' 4.txt | cat -n

root@ubuntu:~# sed -n '/[0-9]/p' 4.txt | cat -n1  who are you 12342  xixi I'm a baby 56783  What are you doing 90
root@ubuntu:~#

显示以xixi开头的数据行:sed -n '/^xixi/p' 4.txt | cat -n

root@ubuntu:~# sed -n '/^xixi/p' 4.txt | cat -n1  xixi I'm a baby 5678
root@ubuntu:~#

扩展正则实例

默认sed不支持扩展正则,如果希望使用扩展正则匹配数据,可以使用-r参数。

输出xixi和who开头的行:执行sed -n '/^(xixi|who)/p' 4.txt,不会看到任何输出,加-r参数:sed -rn '/^(xixi|who)/p' 4.txt

root@ubuntu:~# sed -rn '/^(xixi|who)/p' 4.txt
who are you 1234
xixi I'm a baby 5678
root@ubuntu:~#

正则匹配包含in的行并显示: sed -n '\cincp' 4.txt

root@ubuntu:~# sed -n '\cincp' 4.txt
What are you doing 90
There is a mm in the box
root@ubuntu:~#

正则匹配包含in的行并显示: sed -n '\xinxp' 4.txt

root@ubuntu:~# sed -n '\xinxp' 4.txt
What are you doing 90
There is a mm in the box
root@ubuntu:~#

正则匹配包含in的行并显示: sed -n '\linlp' 4.txt,这里的l是小写的L。

root@ubuntu:~# sed -n '\linlp' 4.txt
What are you doing 90
There is a mm in the box
root@ubuntu:~#

正则匹配包含in的行并显示: sed -n '\:in:p' 4.txt,

root@ubuntu:~# sed -n '\:in:p' 4.txt
What are you doing 90
There is a mm in the box
root@ubuntu:~#

正则匹配包含in的行并显示: sed -n '\,in,p' 4.txt,

root@ubuntu:~# sed -n '\,in,p' 4.txt
What are you doing 90
There is a mm in the box
root@ubuntu:~#

显示数据内容时打印控制字符:sed -n 'l' 4.txt,结果显示每行末尾了"$"。

root@ubuntu:~# sed -n 'l' 4.txt
hello world $
are you ok$
who are you 1234$
xixi I'm a baby 5678$
What are you doing 90$
There is a mm in the box$
root@ubuntu:~#

sed程序使用=指令可以显示行号,结合条件匹配,可以显示特定数据行的行号。

显示包含mm字符串的行号:sed -n '/mm/=' 4.txt

root@ubuntu:~# sed -n '/mm/=' 4.txt
6
root@ubuntu:~#

显示第一行和最后一行的行号:sed -n '1=' 4.txt 和 sed -n '$=' 4.txt

root@ubuntu:~# sed -n '1=' 4.txt
1
root@ubuntu:~# sed -n '$=' 4.txt
6
root@ubuntu:~#

在sed中支持使用感叹号(!)对匹配的条件进行取反操作。

显示除第2行外的其他行的数据:cat -n 4.txt > 5.txt | sed -n '2!p' 5.txt

root@ubuntu:~# cat -n 4.txt > 5.txt | sed -n '2!p' 5.txt1  hello world3  who are you 12344  xixi I'm a baby 56785  What are you doing 906  There is a mm in the box
root@ubuntu:~#

除baby行外的所有行都显示: cat -n 4.txt > 5.txt | sed -n '/baby/!p' 5.txt

root@ubuntu:~# cat -n 4.txt > 5.txt | sed -n '/baby/!p' 5.txt1  hello world2  are you ok3  who are you 12345  What are you doing 906  There is a mm in the box
root@ubuntu:~#

文件修改实例

第6行后面添加一行数据:sed '6a She is alive in the box' 4.txt

root@ubuntu:~# sed '6a She is alive in the box' 4.txt
hello world
are you ok
who are you 1234
xixi I'm a baby 5678
What are you doing 90
There is a mm in the box
She is alive in the box
root@ubuntu:~# 

通过a指令添加新的数据行后,虽然在屏幕的输出结果中我们确实看到了添加的新数据,但是查看源文件后就会发现4.txt并没有实际发生变化,默认sed仅仅是在缓存区中修改了数据并显示在屏幕上,而源文件不会发生变化。如果希望直接修改源文件的话,可以使用-i选项,但是使用该选项修改文件后,万一修改错误,数据将无法被恢复。

使用-i现象修改文件,并查看结果:sed -i '6a She is alive in the box' 4.txt && cat -n 4.txt

root@ubuntu:~# sed -i '6a She is alive in the box' 4.txt && cat -n 4.txt1  hello world2  are you ok3  who are you 12344  xixi I'm a baby 56785  What are you doing 906  There is a mm in the box7  She is alive in the box
root@ubuntu:~#

提示:生产环境中的最佳实践是先不使用-i选项测试sed指令是否正确,确认无误后再使用-i选项修改源文件,或者对源文件进行备份操作。

下面这条命令会先将文件备份为后缀名称为.bak的文件,再修改源文件的内容,将4.txt文件的第7行删除,d指令是以行为单位进行删除的指令。

sed -i.bak '7d' 4.txt && cat -n 4.txt && cat -n 4.txt.bak

root@ubuntu:~# sed -i.bak '7d' 4.txt && cat -n 4.txt && cat -n 4.txt.bak1  hello world2  are you ok3  who are you 12344  xixi I'm a baby 56785  What are you doing 906  There is a mm in the box
#下面是备份文件的内容1  hello world2  are you ok3  who are you 12344  xixi I'm a baby 56785  What are you doing 906  There is a mm in the box7  She is alive in the box
root@ubuntu:~#

在第1行的前面插入数据#!/bin/bash ,不修改源文件:sed -n '1i #!/bin/bash' 4.txt && cat 4.txt

root@ubuntu:~# sed -n '1i #!/bin/bash' 4.txt && cat 4.txt
#!/bin/bash
hello world
are you ok
who are you 1234
xixi I'm a baby 5678
What are you doing 90
There is a mm in the box
root@ubuntu:~#

在第1行的前面插入数据#!/bin/bash,修改源文件 :sed -i '1i #!/bin/bash' 4.txt && cat 4.txt

root@ubuntu:~# sed -i '1i #!/bin/bash' 4.txt && cat 4.txt
#!/bin/bash
hello world
are you ok
who are you 1234
xixi I'm a baby 5678
What are you doing 90
There is a mm in the box
root@ubuntu:~#

下面这条命令是让sed正则匹配包含are的行后面添加新的->big big world数据行。这里需要注意的是,a或者i指令后面的所有内容都会被理解为需要添加的数据内容,因此不可以再写其他指令,效果如下。为了不破坏原始数据,下面的演示都不再使用-i选项。

sed '/are/a ->big big world' 4.txt,由结果可知,共插入了3行。

root@ubuntu:~# sed '/are/a ->big big world' 4.txt
#!/bin/bash
hello world
are you ok
->big big world
who are you 1234
->big big world
xixi I'm a baby 5678
What are you doing 90
->big big world
There is a mm in the box
root@ubuntu:~#

删除全文: sed 'd' 4.txt

删除第一行: sed '1d' 4.txt

删除空白行:sed -i '/^$/d' 4.txt

删除#符号开头的行:sed -i '/^#/d' 4.txt

root@ubuntu:~# sed -i '/^#/d' 4.txt
root@ubuntu:~# cat 4.txt
hello world
are you ok
who are you 1234
xixi I'm a baby 5678
What are you doing 90
There is a mm in the box
root@ubuntu:~#

删除包含are的行:sed '/are/d' 4.txt

替换实例

将第二行整行替换为新内容:sed '2c -->this is a new line' 4.txt

root@ubuntu:~# sed '2c -->this is a new line' 4.txt
hello world
-->this is a new line
who are you 1234
xixi I'm a baby 5678
What are you doing 90
There is a mm in the box
root@ubuntu:~#

将第所有行替换为新内容:sed 'c -->One two three,go!' 4.txt

root@ubuntu:~# sed 'c -->One two three,go!' 4.txt
-->One two three,go!
-->One two three,go!
-->One two three,go!
-->One two three,go!
-->One two three,go!
-->One two three,go!
root@ubuntu:~#

将包含are的行替换为新内容:sed '/are/c -->One two three,go!' 4.txt

root@ubuntu:~# sed '/are/c -->One two three,go!' 4.txt
hello world
-->One two three,go!
-->One two three,go!
xixi I'm a baby 5678
-->One two three,go!
There is a mm in the box
root@ubuntu:~#

我们通过r指令可以将其他文件的内容读取并存入当前需要编辑的文件中。而w指令则将当前编辑的文件内容另存到其他文件中,如果目标文件已存在,则另存时会将目标文件的内容覆盖。创建新文件6.txt,echo "lkmao" > 6.txt

sed 'r 6.txt' 4.txt

root@ubuntu:~# sed 'r 6.txt' 4.txt
hello world
lkmao
are you ok
lkmao
who are you 1234
lkmao
xixi I'm a baby 5678
lkmao
What are you doing 90
lkmao
There is a mm in the box
lkmao
root@ubuntu:~#

为什么每行后面都有lkmao这个内容呢?因为sed是逐行处理工具,在r指令的前面没有写匹配条件,则默认会匹配所有数据行,所以虽然只写了一个r指令读取4.txt文件,但是这条指令会被反复执行N次,读取4.txt文件的第1行会执行一次r指令,接着读取4.txt文件的第2行又会执行一次r指令,依此类推,直到4.txt文件读取结束时程序退出。所以我们看到的结果是每一行后面都追加了lkmao。如果希望每行后面都追加签名,可以在r指定前面添加匹配条件。

仅在第一行后面追加签名:sed '1r 6.txt' 4.txt

root@ubuntu:~# sed '1r 6.txt' 4.txt
hello world
lkmao
are you ok
who are you 1234
xixi I'm a baby 5678
What are you doing 90
There is a mm in the box
root@ubuntu:~# 

将6.txt所有数据行另存为新文件new.txt,并查看new.txt的内容:

sed -n 'w new.txt' 6.txt && cat -n new.txt

root@ubuntu:~# sed -n 'w new.txt' 6.txt && cat -n new.txt1  lkmao
root@ubuntu:~# 

将4.txt1-3行的内容写入new.txt,并查看new.txt的内容:

sed -n '1,3w new.txt' 4.txt && cat -n new.txt

root@ubuntu:~# sed -n '1,3w new.txt' 4.txt && cat -n new.txt1  hello world2  are you ok3  who are you 1234
root@ubuntu:~#

正常情况下sed会在读取完所有数据行之后退出,但是我们可以随时使用q指令来提前退出sed。

警告:一般不要在使用类似于3q之类的指令时同时使用-i选项,这样会导致sed使用读取出来的3行数据,写入并覆盖源文件,从而会导致源文件中所有其他数据全部丢失。

单个词的替换和删除实例

在前面的案例中我们已经学习了使用c和d对数据行进行修改和删除操作,但是这两个指令都以行为单位,c会将整行内容都替换,d则将整行内容都删除。而在实际工作中我们经常需要的是将某个关键词替换(行中的部分内容替换),或者将某个关键词删除,此时就需要使用s指令来完成这样的工作。

准备一个文件interfaces,内容如下所示:

# interfaces(5) file used by ifup(8) and ifdown(8)
auto ens33
iface ens33 inet static
address 192.168.0.11
netmask 255.255.255.0
gateway 192.168.0.1
dns-nameservers 8.8.8.8

修改该文件的ip地址和网关

root@ubuntu:~# sed -i 's/192.168.0.11/192.168.5.25/' interfaces
root@ubuntu:~# sed -i 's/192.168.0.1/192.168.5.1/' interfaces

上面这条命令在s前面没有写匹配条件,因此是匹配所有数据行。当sed读取interfaces文件的第1行时,对该行进行正则匹配192.168.0.1,如果在该行数据中包含192.168.0.1,则将192.168.0.1替换为192.168.5.1,接着读取第2行再次进行正则匹配,第2行没有192.168.0.1,则不进行任何替换,继续读取下一行,依此类推,直到文件结束。

查看修改后的文件:cat interfaces

root@ubuntu:~# cat interfaces
# interfaces(5) file used by ifup(8) and ifdown(8)
auto ens33
iface ens33 inet static
address 192.168.5.25
netmask 255.255.255.0
gateway 192.168.5.1
dns-nameservers 8.8.8.8
root@ubuntu:~#

仅对第一行执行替换操作,将world替换为lkmao:sed '1s/world/lkmao/' 1.txt

root@ubuntu:~# sed '1s/world/lkmao/' 1.txt
hello lkmao
are you ok
root@ubuntu:~#

仅替换每行中的第一个o:sed 's/o/O/' 1.txt

root@ubuntu:~# sed 's/o/O/' 1.txt
hellO world
are yOu ok
root@ubuntu:~#

上面这条命令会逐行读取1.txt文件内容,将小写的字母o替换为大写字母O,但是我们会发现如果一行中有多个字母o, sed默认仅仅会将第一个字母o替换为大写。如果需要替换每行中所有的小写字母o,则需要在s指令的末尾追加一个g标记,当然也运行我们追加一个具体的数据,表示对第几个字母o进行替换操作。

替换每行中的所有字母o:sed 's/o/O/g' 1.txt

root@ubuntu:~# sed 's/o/O/g' 1.txt
hellO wOrld
are yOu Ok
root@ubuntu:~#

仅替换每行中的第二个o:sed 's/o/O/2' 1.txt

root@ubuntu:~# sed 's/o/O/2' 1.txt
hello wOrld
are you Ok
root@ubuntu:~#

仅显示被替换的数据行:sed -n 's/a/A/p' 1.txt

root@ubuntu:~# sed -n 's/a/A/p' 1.txt
Are you ok
root@ubuntu:~#

在s替换指令的最后添加i标记可以忽略大小写,下面这条命令可以将大小写的WORLD都转换为lkmao。sed -i 's/WORLD/lkmao/i' 1.txt && cat 1.txt

root@ubuntu:~# sed -i 's/WORLD/lkmao/i' 1.txt && cat 1.txt
hello lkmao
are you ok
root@ubuntu:~#

使用s替换指令时如果同时添加了e标记,则表示将替换后的内容当成Shell命令在终端执行一次。下面第一条sed命令是将1.txt替换为ls -lsh 1.txt,替换后在命令终端执行ls -lsh 1.txt,因此屏幕输出的是该文件的详细信息。下面第二条sed命令是将lkmao.txt替换为touch lkmao.txt,替换后在命令终端执行该命令,最后使用ls -lsh lkmao.txt查看系统中是否已经创建了该文件。

root@ubuntu:~# echo "1.txt" | sed 's/^/ls -lsh /e'
4.0K -rw-r--r-- 1 root root 23 11月  8 15:24 1.txt
root@ubuntu:~#echo "lkmao.txt" | sed 's#^#touch #e'root@ubuntu:~# ls -lsh lkmao.txt
0 -rw-r--r-- 1 root root 0 11月  8 16:14 lkmao.txt
root@ubuntu:~#

将hello替换为空,即删除:sed 's/hello//' 1.txt

root@ubuntu:~# sed 's/hello//' 1.txtlkmao
are you ok
root@ubuntu:~#

下面这两个替换是有区别的,第一个替换是在匹配双引号开头双引号结尾和中间所有数据,并将其替换为1;而第二个替换仅仅是在匹配由一个引号开始,中间是不包含引号的任意其他字符(长度任意),最后是一个双引号结束的数据,这样当一行数据中包含多个引号数据时,就可以仅仅匹配第一个双引号的数据。

root@ubuntu:~# echo '"hello" "world"'
"hello" "world"
lkmao@ubuntu:~$ echo '"hello" "world"' | sed 's/\".*\"/1/'
1
lkmao@ubuntu:~$ echo '"hello" "world"' | sed 's/\"[^\"]*\"/1/'
1 "world"
lkmao@ubuntu:~$

下面这条命令应用了正则表达式中的保留功能,使用圆括号将匹配的数据保留,在后面通过\n调用前面保留的数据。这里在第一个圆括号中保留的是每行开头的第一个字符(.在正则中表示任意单个字符),在第三个圆括号中保留的是每行结束的最后一个字符,而在中间第二个圆括号中保留的是除首尾字符外中间的所有字符(.*在正则中表示任意长度的任意字符)。因为都是使用任意字符进行匹配,所以这三个括号可以匹配所有行的数据,并在后面将匹配的数据顺序进行重新调整再输出,将第三个括号的数据(\3)先输出,再输出第二个括号中的数据(\2),最后输出的是第一个括号中的数据(\1)。

实例:将一行的第一个字符和最后一个字符互相替换。

这个敲了好多遍才敲对,究其原因,还在于刚开始的时候,没想明白这一堆符号的作用。

root@ubuntu:~# sed -r 's/^(.)(.*)(.)$/\3\2\1/' 1.txt
oello lkmah
kre you oa
root@ubuntu:~#

在使用s指令进行替换时默认我们使用斜线(/)作为替换符号,但是当我们需要替换的内容本身包含斜线时就比较麻烦,需要对替换内容中的斜线使用右斜线(\)转义,这种情况下编写sed命令会很痛苦,读这样的代码更是让人崩溃。为了解决类似的问题,sed支持使用任何其他字符作为替换符号。下面的案例我们希望将/home/lkmao/替换为/root/。

准备一个新的测试文件echo "/home/lkmao/ is a directory" > 7.txt

root@ubuntu:~# echo "/home/lkmao/ is a directory" > 7.txt
root@ubuntu:~# cat 7.txt
/home/lkmao/ is a directory
root@ubuntu:~#

将/home/lkmao/ 替换为 /root/

root@ubuntu:~# sed 's/\/home\/lkmao\//\/root\//' 7.txt
/root/ is a directory
root@ubuntu:~#

这样的命令不管是自己编写,还是让别人阅读都绝对如恶梦一般!下面我们将s指令的替换符号修改为其他字符试试。

警号'#'作为替换符:sed 's#/home/lkmao/#/root/#' 7.txt

root@ubuntu:~# sed 's#/home/lkmao/#/root/#' 7.txt
/root/ is a directory
root@ubuntu:~#

逗号','作为替换符:sed 's,/home/lkmao/,/root/,' 7.txt

root@ubuntu:~# sed 's,/home/lkmao/,/root/,' 7.txt
/root/ is a directory
root@ubuntu:~#

字母y作为替换符::sed 'sy/home/lkmao/y/root/y' 7.txt

root@ubuntu:~# sed 'sy/home/lkmao/y/root/y' 7.txt
/root/ is a directory
root@ubuntu:~#

数字8作为替换符:sed 's8/home/lkmao/8/root/8' 7.txt

数字7作为替换符:sed 's7/home/lkmao/7/root/7' 7.txt

root@ubuntu:~# sed 's8/home/lkmao/8/root/8' 7.txt
/root/ is a directory
root@ubuntu:~# sed 's7/home/lkmao/7/root/7' 7.txt
/root/ is a directory
root@ubuntu:~#

使用sed时可以使用分号或者-e选项两种方式在一行中编写多条指令。可以直接使用分号将多个指令分隔,或者在多个-e参数后面添加sed指令,sed支持一个或多个-e参数。如果将分号放到花括号中还可以实现对指令进行分组。

root@ubuntu:~# sed -n '1p;3p;5p' 4.txt
hello world
who are you 1234
What are you doing 90
root@ubuntu:~# cat -n 4.txt > 5.txt | sed -n '1p;3p;5p' 5.txt1  hello world3  who are you 12345  What are you doing 90
root@ubuntu:~#

同时替换hello为hi和删除are:sed '/world/s/hello/hi/; s/are//' 4.txt

root@ubuntu:~# sed '/world/s/hello/hi/; s/are//' 4.txt
hi worldyou ok
who  you 1234
xixi I'm a baby 5678
What  you doing 90
There is a mm in the box
root@ubuntu:~#

查找world行,替换该行的hello为hi,并删除world:sed '/world/{s/hello/hi/; s/world//}' 4.txt

root@ubuntu:~# sed '/world/{s/hello/hi/; s/world//}' 4.txt
hi
are you ok
who are you 1234
xixi I'm a baby 5678
What are you doing 90
There is a mm in the box
root@ubuntu:~#

上面这两条命令在不使用分组功能时,系统会先找到包含world的行,然后将该行数据中的are删除,因为直接使用分号分隔了多条指令,匹配条件仅对第一个指令有效,第二个指令在没有匹配条件的情况下会匹配所有的数据行,只要数据行中包含are就删除,因此不使用分组时第2、3、5行的are都被删除了。而使用分组的最大好处就是在满足匹配条件时执行一组指令,而不满足匹配条件时不会执行这组指令,此时这个匹配条件会对分组中的所有指令有效,上面第二个sed会先找到包含world的行,然后针对这一行的数据将hello替换为hi,将are删除,因此最终仅对4.txt文件的第一行执行分组指令。

下面指令的含义:匹配第一行数据后将整行内容替换为hello lkmao;匹配第二行数据,先显示该行中的所有数据,再将该行中的第一个小写字母a替换为大写字母A;使用正则匹配包含数据的行并将该行的所有数据都删除;最后使用正则匹配包含mm的行,先将该行中第一个小写字母i替换为大写字母I,然后将该行中的mm替换为maomi,然后将该行中的box替换为cup(仅对包含mm的行执行三个s替换指令)。

root@ubuntu:~# cat 4.txt
hello world
are you ok
who are you 1234
xixi I'm a baby 5678
What are you doing 90
There is a mm in the box
root@ubuntu:~# cat script.sed
1c hello lkmao
2{ps/g/G/
}
/[0-9]/d
/mm/{s/mm/maomi/s/box/cup/
}
root@ubuntu:~# sed -f script.sed 4.txt
hello lkmao
are you ok
Are you ok
There Is a maomi in the cup
root@ubuntu:~#

小结

sed学习与实践1:sed基本指令相关推荐

  1. Shell学习总结-流编辑器sed

    目录 正则表达式 定址 命令与选项 用sed修改文件 元字符 sed范例 106- 正则表达式 与grep一样,sed在文件中查找模式时也要使用正则表达式(RE)和各种元字符.正则表达式是括在斜杠间的 ...

  2. linux sed写文件内容,Linux学习——文本处理:sed

    事先说明,这是我在跟随老师学习过程中,从老师笔记中吸取的一点点经验,有很多都是老师笔记上的.我写这个博客,更多的是记录自己的学习过程,不喜勿碰. 一个超级有脑洞的流编辑器:sed ps:反正我个人认为 ...

  3. linux sed替换文件,linux的sed命令替换文件

    linux下的sed是一个强大的编辑器工具,下面由学习啦小编为大家整理了linux的sed命令替换文件的相关知识,希望对大家有帮助! linux的sed命令替换文件 sed在Linux下是个强大的工具 ...

  4. sed基本用法 sed文本块处理 、 sed高级应用

    sed 文本编辑器(vim) 增,删,改,查 特色:流处理器[逐行处理的流处理器] 各种编辑器notepad,notepad++,word,atom vim,vi,gedit,sed 非交互的(sed ...

  5. 组队学习-NLP实践-中文预训练模型泛化能力挑战赛(文本分类,bert)

    组队学习-NLP实践-中文预训练模型泛化能力挑战赛 Docker 安装与使用 阿里云镜像仓库 baseline 本机运行并提交 Docker 安装与使用 参考:https://mp.weixin.qq ...

  6. 演讲实录:百度大规模深度学习应用实践和开源AI框架PaddlePaddle

    导语:本文根据PaddlePaddle技术负责人.百度NLP技术委员会主席于佃海在今年英特尔人工智能大会上的演讲--<百度大规模深度学习应用实践和开源AI框架PaddlePaddle>整理 ...

  7. 【转载】演讲实录:百度大规模深度学习应用实践和开源AI框架PaddlePaddle

    导语:本文根据PaddlePaddle技术负责人.百度NLP技术委员会主席于佃海在今年英特尔人工智能大会上的演讲--<百度大规模深度学习应用实践和开源AI框架PaddlePaddle>整理 ...

  8. 变量存储重温与Clion编辑器的学习与实践

    变量存储重温与Clion编辑器的学习与实践 一.实验要求 二.变量存储重温 1.内存分配 (1)内存属性简述 (2)内存分区简述 (3)分区进行对比 (4)STM32数据存储位置 2.编程进行验证 ( ...

  9. 八大深度学习最佳实践

    翻译 | AI科技大本营 参与 | 刘畅 [AI 科技大本营导读] 2017年,许多的人工智能算法得到了实践和应用.名博Hack Noon作者 Brian Muhia 认为想要玩转人工智能,不仅要拥有 ...

最新文章

  1. 在虚拟机中快速安装 Ubuntu 18.04
  2. RabbitMQ创建远程连接用户
  3. 笔记-项目管理基础知识-复习要点
  4. 打桩时不修改源码_考研网上报名点了修改报名,修改后到报名点时,出现部分信息不符合参考条件,请修改或重新报名...
  5. 小程序资源服务器,开发小程序没有服务器资源
  6. asp代码在dwearwear转换成html格式怎么转,为前端而生的编辑器Brackets及配置推荐
  7. elementUI 分页器使用时遇到的Bug
  8. Mysql表的约束设计和关联关系设计
  9. mysql maxwait_数据库连接池 maxActive,maxIdle,maxWait参数
  10. mysql开发与运维_专业的MySQL开发规范
  11. CSDN新版下载频道介绍之二——上传和下载资源页面介绍
  12. oracle基础语法(二)ORACLE查询
  13. 你们那有个计算机室吗英语,关于电脑的英语作文80字
  14. OPPO,ViVO手机锁屏下弹出来电界面
  15. 跨专业考c语言程序设计,多位跨考大神,教你如何跨专业上岸
  16. mysql 执行delete引发死锁问题
  17. [高项]工作绩效数据 vs工作绩效信息 vs工作绩效报告
  18. Geoffrey Hinton
  19. Django入门-6:视图-HttpReqeust对象
  20. 国科大学习资料--最优化计算方法(王晓)--期末考试试卷1

热门文章

  1. AI-K210 开发家庭万用宝模组(1)
  2. 利用计算机设计轴对称图案,“轴对称图形”信息技术应用设计与分析|轴对称图形有哪些图片...
  3. 人生感悟--条条经典
  4. 首次使用Neptune3000海底静力触探CPT记录
  5. 婚宴座位图html5,婚宴怎么安排座位 结婚喜宴座位安排图
  6. debian 安装wine
  7. 编程爱好者网站试题中心 的一道题:关于*(p++)
  8. B站后台源代码泄露,官方回应声明黑话指南
  9. 腐肉为引,气球为信,负重前行,只为爱你
  10. 每天进步一点之灵魂拷问14之网络连接2