sed命令

​全称Stream Editor
功能是增删改文本

sed处理数据的顺序如下:
1.每次仅读取一行内容;
2.根据提供的命令处理数据。注意,sed 默认不会直接修改源文件数据,而是会将数据复制到缓冲区中,修改也仅限于缓冲区中的数据;缓冲区叫做模式空间
3.将结果输出。

当一行数据处理完成后,它会继续读取下一行数据,并重复这个过程,直到将文件中所有数据处理完毕。无论脚本命令是什么,所有的行都读取一遍。

一、语法格式

用法: sed 选项 脚本 文件

二、选项

-n, --quiet, --silent     取消自动打印模式空间
--debug     对程序运行进行标注
-e 脚本, --expression=脚本     添加“脚本”到程序的运行列表
-f 脚本文件, --file=脚本文件     添加“脚本文件”到程序的运行列表
--follow-symlinks     直接修改文件时跟随软链接
-i[扩展名], --in-place[=扩展名]     直接修改文件(如果指定扩展名则备份文件)
-l N, --line-length=N     指定“l”命令的换行期望长度
--posix     关闭所有 GNU 扩展
-E, -r, --regexp-extended     在脚本中使用扩展正则表达式(为保证可移植性使用 POSIX -E)。
-s, --separate     将输入文件视为各个独立的文件而不是单个长的连续输入流。
--sandbox     在沙盒模式中进行操作(禁用 e/r/w 命令)。
-u, --unbuffered     从输入文件读取最少的数据,更频繁的刷新输出
-z, --null-data     使用 NUL 字符分隔各行
--help 打印帮助并退出
--version 输出版本信息并退出

三、参数

(一)脚本

格式为:

'[address]命令'

或者

'[address] {命令1;命令2...}'

为了避免shell先解析特殊字符,脚本一般都要加单引号。
如果是执行多条脚本,格式为:

'[addr1]{命令1};[addr2]{命令2}...'

1.address


address可以是下列情况:
(1)直接省略,表示处理全文
(2)单地址
n——数字,表示第n行
$——是特殊的标记,表示最后一行。1匹配第一行,而不是^,这点和正则不大一样。
/pattern/——pattern为正则表达式,sed规定两端必须要加//。表示匹配此模式的每一行。正则表达式为基本正则表达式。
first~step——从first行开始,每隔step行执行一次命令
(3)地址对
n1,n2——从第n1行到第n2行
n1,+n2——从n1行开始的n2行
/pattern1/,/pattern2/——从匹配pattern1的行到匹配pattern2的行
n1,/pattern1/ ——从第n1行到匹配pattern1的行
addr1,~N——从匹配的addr1行开始,直到某一行,该行的行号是N的倍数为止。

每一地址对的匹配机制,都有一个状态变量。它有三种状态:没进入匹配,进入匹配,离开匹配
一开始状态是没进入匹配,所以新读入行的行号要与addr1比较,如果大于addr1,则进入匹配,处理完读下一行;如果小于addr1,则不匹配,那还是没进入匹配状态,读下一行。
当状态是进入匹配时,新读入行的行号要与addr2比较,小于addr2,则匹配,处理完读下一行;大于addr2,则不匹配,离开匹配,读下一行。之后都是离开匹配状态,一直处于不匹配状态。

2.命令

a\ # 在当前行下面插入文本。
i\ # 在当前行上面插入文本。
c\ # 把选定的行改为新的文本。
d # 删除,删除选择的行。
D # 删除模板块的第一行。
s # 替换指定字符
h # 拷贝模板块的内容到内存中的缓冲区。
H # 追加模板块的内容到内存中的缓冲区。
g # 获得内存缓冲区的内容,并替代当前模板块中的文本。
G # 获得内存缓冲区的内容,并追加到当前模板块文本的后面。
l # 列表不能打印字符的清单。
n # 读取下一个输入行,用下一个命令处理新的行而不是用第一个命令。
N # 追加下一个输入行到模板块后面并在二者间嵌入一个新行,改变当前行号码。
p # 打印模板块的行。
P # (大写) 打印模板块的第一行。
q # 退出Sed。
b lable # 分支到脚本中带有标记的地方,如果分支不存在则分支到脚本的末尾。
r file # 从file中读行。
t label # if分支,从最后一行开始,条件一旦满足或者T,t命令,将导致分支到带有标号的命令处,或者到脚本的末尾。
T label # 错误分支,从最后一行开始,一旦发生错误或者T,t命令,将导致分支到带有标号的命令处,或者到脚本的末尾。
w file # 写并追加模板块到file末尾。
W file # 写并追加模板块的第一行到file末尾。
! # 表示后面的命令对所有没有被选定的行发生作用。
= # 打印当前行号码。
# #把注释扩展到下一个换行符以前。

(二)文件


指定待处理的文本文件列表。

四、示例用法

(一)s 命令


把匹配到的字符串替换成指定字符串。
此命令格式为:

'[address]s/pattern/replacement/[flags]'

1.address
address 表示指定要操作的具体行

2.pattern
pattern 指的是需要替换的内容,正则表达式是基本正则表达式BRE,像+等要在前面加转义符号
sed不支持非贪婪模式

3.replacement
replacement 指的是要替换成的新内容。
replacement中的特殊符号
(1)&
& 代表每一个所匹配到的内容:

echo this is a test line | sed 's/\w\+/[&]/g'
[this] [is] [a] [test] [line]

正则表达式 \w+ 匹配每一个单词,使用 [&] 替换它

sed 's/^192.168.0.1/&localhost/' file
192.168.0.1localhost

以192.168.0.1开头的行都会被替换成它自已加localhost

(2)\n
\1代表匹配到第一个括号内的内容

echo this is digit 7 in a number | sed 's/digit \([0-9]\)/\1/'
this is 7 in a number
digit 7替换成了 7。
echo aaa BBB | sed 's/\([a-z]\+\) \([A-Z]\+\)/\2 \1/'
BBB aaa
sed -n 's/\(love\)able/\1rs/p' file
love被标记为1,所有loveable会被替换成lovers,并打印出来
grep -o -E '"[^" ]+.gif"' view.html | sed 's/"\(.\+\)"/\1/'
查找所有gif链接,把双引号都去掉

4.字符 /
在sed中作为定界符使用,也可以使用其他任意字符作为定界符:

sed 's:test:TEXT:g'
sed 's|test|TEXT|g'

定界符出现在样式内部时,需要进行转义:

sed 's/\/bin/\/usr\/local\/bin/g'

5.flags
flags有如下几个:
(1)n标记
1~512之间的数字。指定替换第几处匹配的字符串:

sed 's/test/trial/2' data4.txt
使用数字 2 作为标记的结果就是,sed 编辑器只替换每行中第 2 次出现的匹配模式。

(2)g标记
替换所有匹配的字符串,如果没有 g,则只会替换第一个匹配

sed 's/test/trial/g' data4.txt

(3)p标记
我们知道,-n 选项会禁止 sed 输出,但 p 标记会输出修改过的行,将二者结合使用就是只输出被替换命令修改过的行,例如:

sed -n 's/test/trial/p' data5.txt

(4)w标记
w 标记会将替换后的结果保存到指定文件中:

sed 's/test/trial/w test.txt' data5.txt

(二)d命令


删除指定内容
此命令的基本格式为:

'[address]d'
sed 'd' data1.txt
如果不指定具体行的话,文件中的所有内容都会被删除

sed '3d' data6.txt

删除 data6.txt 文件内容中的第 3 行
sed '2,3d' data6.txt

删除 data6.txt 文件内容中的第 2、3行
sed '3,$d' data6.txt

删除 data6.txt 文件内容中第 3 行到最后一行的内容

(三)a i 命令


a 命令表示在指定行的后面附加一行,i 命令表示在指定行的前面插入一行,这里之所以要同时介绍这 2 个脚本命令,因为它们的基本格式完全相同,如下所示:

'[address]a(或 i)\新文本内容'

实际测试,加不加\效果是一样的。

sed '/^test/a\this is a test line' file
将 this is a test line 追加到 以test 开头的行后面

sed '2a\this is a test line' test.conf
在 test.conf 文件第2行之后插入 this is a test line

sed '/^test/i\this is a test line' file
将 this is a test line 追加到以test开头的行前面

sed '5i\this is a test line' test.conf
在test.conf文件第5行之前插入this is a test line

sed '3ichange' test.txt
在第3行前插入一行change

(四)c 命令


将指定行替换成指定字符串。
该命令的基本格式为:

[address]c\用于替换的新文本

实际测试,加不加\效果是一样的。

sed '3cchange' test.txt
将第3行替换成change

(五)y 命令


y 转换命令是唯一可以处理单个字符的 sed 脚本命令,其基本格式如下:

'[address]y/inchars/outchars/'

转换命令会依次把inchars中字符转换到outchars中的字符。如果 inchars 和 outchars 的长度不同,则 sed 会产生一条错误消息。

sed 'y/123/789/' data8.txt
将1替换成7,2替换成8,3替换成9

echo "This 1 is a test of 1 try." | sed 'y/123/456/'
This 4 is a test of 4 try.
sed 转换了在文本行中匹配到的字符 1 的两个实例,我们无法限定只转换在特定地方出现的字符。

(六)p 命令


输出该行的内容,此命令的基本格式为:

'[address]p'
sed -n '/number 3/p' data6.txt
This is line number 3.
用 -n 选项和 p 命令配合使用,我们可以禁止输出其他行,只打印包含匹配文本模式的行。


sed -n '/3/{p; s/line/test/p}' data6.txt
This is line number 3.
This is test number 3.
sed 命令会查找包含数字 3 的行,然后执行两条命令。
首先,脚本用 p 命令来打印出原始行;
然后用 s 命令替换文本,并用 p 标记打印出替换结果。输出同时显示了原来的行文本和新的行文本。

(七)w 命令


w 命令用来将文本中指定行的内容写入文件中,此命令的基本格式如下:

'[address]w filename'

这里的 filename 表示文件名,可以使用相对路径或绝对路径,但不管是哪种,运行 sed 命令的用户都必须有文件的写权限。

sed '1,2w test.txt' data6.txt
将前两行写到一个文本文件中

(八)r 命令


r 命令用于将一个文件的数据插入到指定位置,该命令的基本格式为:

'[address]r filename'
sed '3r data12.txt' data6.txt
将 filename 文件中的内容插入到 address 指定行的后面

sed '$r data12.txt' data6.txt
将指定文件中的数据插入到数据流的末尾

(九)q 命令


q 命令的作用是使 sed 命令在第一次匹配任务结束后,退出 sed 程序,不再处理后续数据。

格式:

'[address]q'
sed '2q' test.txt
This is line number 1.
This is line number 2.
sed 命令在打印输出第 2 行之后,就停止了,是 q 命令造成的


sed '/number 1/{ s/number 1/number 0/;q; }' test.txt
This is line number 0.
使用 q 命令之后,sed 命令会在匹配到 number 1 时,将其替换成 number 0,然后直接退出。

(十)n命令


移动到匹配的下一行

格式:

'[address]n'
sed '/test/{ n; s/aa/bb/; }' file
找到包含test的行,再移动到下一行,替换这一行的aa,变为bb,并打印该行,然后继续

(十一)-n选项


不打印模式空间
因为sed默认处理完一行就打印一行,所以如果不想打印,那就使用-n选项

sed -n '/SCC/{n;p}' URFILE
打印匹配字符串的下一行

sed -n 'p;n' test.txt #奇数行
sed -n 'n;p' test.txt #偶数行
sed -n '1~2p' test.txt #奇数行
sed -n '2~2p' test.txt #偶数行
打印奇数行或偶数行

(十二)-e选项


以指定命令处理行,允许在同一行里执行多条命令:

sed -e '1,5d' -e 's/test/check/' file
第一条命令删除1至5行,第二条命令用check替换test。

和 -e 等价的选项是 --expression:

sed --expression='s/test/check/' --expression='/love/d' file

以下两种情况结果为什么会不一样:

$ seq 6 | sed '1,2d' | sed '1,2d' # 结果返回5 6
$ seq 6 | sed -e '1,2d' -e '1,2d' # 结果返回4 5 6

显然这两种情况使用sed的命令形式是不一样的,第一种利用管道使用了sed两次,结果返回5 6,没什么问题;第二种情况在同一个sed命令中使用了两次1,2d,按常理应该是返回 3 4 5 6,结果返回 4 5 6,第3行竟然也被意外地删除了,为什么呢?
解释:
首先第一行被读入,遇到第一组expression -> 1, 2d,第一行匹配成功(进入匹配),执行d命令,d命令清空模式空间的内容,因此不会再执行接下来的命令。
继续从标准输入读入第二行,同1
读入第三行,第一组expression匹配失败(因为3>2,离开匹配),因此试着执行第二组expersson->1,2d,因为这第二个地址对是处于没进入匹配状态,所以要把新读入行号与addr1比较,也就是3>1,所以进入匹配,执行d。(这里是关键)
读入第四行,因为第一个地址对已经是离开匹配状态,所以不再考虑,只执行第二组expersson->1,2d,因为4>2,匹配失败,离开匹配,同时也不执行d。
读入第五、六行,第一个地址对,和第二个地址对,都是离开匹配状态,所以都不执行。因此,最后第1 2 3行被删除。

(十三)-f选项


sed脚本是一个sed的命令清单,启动Sed时以-f选项引导脚本文件名。
Sed对于脚本中输入的命令非常挑剔,在命令的末尾不能有任何空白或文本,如果在一行中有多个命令,要用分号分隔。以#开头的行是注释行,且不能跨行。

sed -f scriptfile file

(十四)-i选项


直接修改原文件

(十五)N命令:将数据流中的下一行加进来创建一个多行组来处理。
N 命令会将下一行文本内容添加到缓冲区已有数据之后(之间用换行符分隔),从而使前后两个文本行同时位于缓冲区中,sed 命令会将这两行数据当成一行来处理。

下面这个例子演示的 N 命令的功能:

[root@localhost ~]# cat data2.txt
This is the header line.
This is the first data line.
This is the second data line.
This is the last line.
[root@localhost ~]# sed '/first/{ N ; s/\n/ / }' data2.txt
This is the header line.
This is the first data line. This is the second data line.
This is the last line.

在这个例子中,sed 命令查找含有单词 first 的那行文本。找到该行后,它会用 N 命令将下一行合并到那行,然后用替换命令 s 将换行符替换成空格。结果是,文本文件中的两行在 sed 的输出中成了一行。

如果要在数据文件中查找一个可能会分散在两行中的文本短语,如何实现呢?这里给大家一个实例:

[root@localhost ~]# cat data3.txt
On Tuesday, the Linux System
Administrator's group meeting will be held.
All System Administrators should attend.
Thank you for your attendance.
[root@localhost ~]# sed 'N ; s/System.Administrator/Desktop User/' data3.txt
On Tuesday, the Linux Desktop User's group meeting will be held.
All Desktop Users should attend.
Thank you for your attendance.

用 N 命令将发现第一个单词的那行和下一行合并后,即使短语内出现了换行,你仍然可以找到它,这是因为,替换命令在 System 和 Administrator之间用了通配符(.)来匹配空格和换行符这两种情况。但当它匹配了换行符时,它就从字符串中删掉了换行符,导致两行合并成一行。这可能不是你想要的。

要解决这个问题,可以在 sed 脚本中用两个替换命令,一个用来匹配短语出现在多行中的情况,一个用来匹配短语出现在单行中的情况,比如:

[root@localhost ~]# sed 'N
> s/System\nAdministrator/Desktop\nUser/
> s/System Administrator/Desktop User/
> ' data3.txt
On Tuesday, the Linux Desktop
User's group meeting will be held.
All Desktop Users should attend.
Thank you for your attendance.

第一个替换命令专门查找两个单词间的换行符,并将它放在了替换字符串中。这样就能在第一个替换命令专门在两个检索词之间寻找换行符,并将其纳入替换字符串。这样就允许在新文本的同样位置添加换行符了。

但这个脚本中仍有个小问题,即它总是在执行 sed 命令前将下一行文本读入到缓冲区中,当它到了最后一行文本时,就没有下一行可读了,此时 N 命令会叫 sed 程序停止,这就导致,如果要匹配的文本正好在最后一行中,sed 命令将不会发现要匹配的数据。

解决这个 bug 的方法是,将单行命令放到 N 命令前面,将多行命令放到 N 命令后面,像这样:

[root@localhost ~]# sed '
> s/System Administrator/Desktop User/
> N
> s/System\nAdministrator/Desktop\nUser/
> ' data3.txt
On Tuesday, the Linux Desktop
User's group meeting will be held.
All Desktop Users should attend.
Thank you for your attendance.

现在,查找单行中短语的替换命令在数据流的最后一行也能正常工作,多行替换命令则会负责短语出现在数据流中间的情况。

(十六)D 多行删除命令


sed 不仅提供了单行删除命令(d),也提供了多行删除命令 D,其作用是只删除缓冲区中的第一行,也就是说,D 命令将缓冲区中第一个换行符(包括换行符)之前的内容删除掉。

比如说:

[root@localhost ~]# cat data4.txt
On Tuesday, the Linux System
Administrator's group meeting will be held.
All System Administrators should attend.
[root@localhost ~]# sed 'N ; /System\nAdministrator/D' data4.txt
Administrator's group meeting will be held.
All System Administrators should attend.

文本的第二行被 N 命令加到了缓冲区,因此 sed 命令第一次匹配就是成功,而 D 命令会将缓冲区中第一个换行符之前(也就是第一行)的数据删除,所以,得到了如上所示的结果。

下面的例子中,它会删除数据流中出现在第一行前的空白行:

[root@localhost ~]# cat data5.txt

This is the header line.
This is a data line.

This is the last line.
[root@localhost ~]# sed '/^$/{N ; /header/D}' data5.txt
This is the header line.
This is a data line.

This is the last line.

sed会查找空白行,然后用 N 命令来将下一文本行添加到缓冲区。此时如果缓冲区的内容中含有单词 header,则 D 命令会删除缓冲区中的第一行。

(十七)P 多行打印命令


同 d 和 D 之间的区别一样,P(大写)命令和单行打印命令 p(小写)不同,对于具有多行数据的缓冲区来说,它只会打印缓冲区中的第一行,也就是首个换行符之前的所有内容。

例如,test.txt 文件中的内容如下:

[root@localhost ~]# cat test.txt
aaa
bbb
ccc
ddd
eee
fff

表 1 中是对 test.txt分别用 p 命令和 P 命令后,产生的输出信息。

表 1 P 命令和 p 命令的对比
P(大写)命令p(小写)命令
[root@localhost ~]# sed '/.*/N;P' test.txt
aaa
aaa
bbb
ccc
ccc
ddd
eee
eee
fff


 
[root@localhost ~]# sed '/.*/N;p' test.txt
aaa
bbb
aaa
bbb
ccc
ddd
ccc
ddd
eee
fff
eee
fff


第一个 sed 命令,每次都使用 N 将下一行内容追加到缓冲区内容的后面(用换行符间隔),也就是说,第一次时缓冲区中的内容为 aaa\nbbb,但 P(大写) 命令的作用的打印换行符之前的内容,也就是 aaa,之后则是 sed 在自动输出功能输出 aaa 和 bbb(sed 命令会自动将 \n 输出为换行),依次类推,就输出了所看到的结果。

第二个 sed 命令,使用的是 p (小写)单行打印命令,它会将缓冲区中的所有内容全部打印出来(\n 会自动输出为换行),因此,出现了看到的结果。

(十八)sed 保持空间

前面我们一直说,sed 命令处理的是缓冲区中的内容,其实这里的缓冲区,应称为模式空间。值得一提的是,模式空间并不是 sed 命令保存文件的唯一空间。sed 还有另一块称为保持空间的缓冲区域,它可以用来临时存储一些数据。

表 2 列出了 5 条可用来操作保持空间的命令。
 

表 2 sed 保持空间命令
命令功能
h将模式空间中的内容复制到保持空间
H将模式空间中的内容附加到保持空间
g将保持空间中的内容复制到模式空间
G将保持空间中的内容附加到模式空间
x交换模式空间和保持空间中的内容


通常,在使用 h 或 H 命令将字符串移动到保持空间后,最终还要用 g、G 或 x 命令将保存的字符串移回模式空间。保持空间最直接的作用是,一旦我们将模式空间中所有的文件复制到保持空间中,就可以清空模式空间来加载其他要处理的文本内容。

由于有两个缓冲区域,下面的例子中演示了如何用 h 和 g 命令来将数据在 sed 缓冲区之间移动。

[root@localhost ~]# cat data2.txt
This is the header line.
This is the first data line.
This is the second data line.
This is the last line.
[root@localhost ~]# sed -n '/first/ {h ; p ; n ; p ; g ; p }' data2.txt
This is the first data line.
This is the second data line.
This is the first data line.

这个例子的运行过程是这样的:

sed脚本命令用正则表达式过滤出含有单词first的行;
当含有单词 first 的行出现时,h 命令将该行放到保持空间;
p 命令打印模式空间也就是第一个数据行的内容;
n 命令提取数据流中的下一行(This is the second data line),并将它放到模式空间;
p 命令打印模式空间的内容,现在是第二个数据行;
g 命令将保持空间的内容(This is the first data line)放回模式空间,替换当前文本;
p 命令打印模式空间的当前内容,现在变回第一个数据行了。

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值