sed是一种流编辑器,它一次处理一行内容。处理时,把当前处理的行存储在临时缓冲区中,又被称为模式空间,接着用sed命令处理缓冲区中的内容,处理完成后,把缓冲区的内容送往屏幕。接着处理下一行,这样不断重复,直到文件末尾。文件内容并没有改变,除非你使用重定向存储输出。
sed命令在处理文件的时候先要找到用户指定的位置,如用户想使用sed替换第二行的内容为mars
,那么它首先需要定位第二行在哪里。默认情况下,sed 命令会作用于文本数据的所有行。如果只想将命令作用于特定行或某些行,则必须写明地址部分[address]
。表示的方法有以下 2 种:
sed '2,3s/dog/cat/' test.sh // 其中的数字2,3就是定位第2、3行,该命令其他的部分后续会进行详细说明
/
包起来。sed '/demo/s/bash/csh/' /etc/passwd // 寻找到以含有demo那一行数据,该命令其他的部分后续会进行详细说明
基本语法如下:
sed 选项参数 命令模式 file
现象参数如下表:
选项参数 | 功能 |
---|---|
-e | 直接在指令列模式上进行sed的工作编辑 |
-f | 该选项会将其后文件中的脚本命令添加到已有的命令中 |
-n | 默认情况下,sed 会在所有的脚本执行完毕后,会自动输出处理后的内容,而该选项会屏蔽自动输出,需使用 print 命令来完成输出 |
-i | 此选项会直接修改源文件 |
命令参数如下表:
命令 | 功能描述 |
---|---|
a | 新增,a的后面可以接子串,在下一行出现,前面接数字即新增在那一行的之后 |
d | 删除,前面加数字即代表删除那一行 |
s | 查找并替换 |
n | 1~512 之间的数字,表示指定要替换的字符串出现第几次时才进行替换,例如,一行中有 3 个 A,但用户只想替换第二个 A,这时就用到这个标记 |
g | 对数据中所有匹配到的内容进行替换,如果没有 g,则只会在第一次匹配成功时做替换操作。例如,一行数据中有 3 个 A,则只会替换第一个 A |
y | y/inchars/outchars/ ,处理单个字符,对 inchars 和 outchars 值进行一对一的映射 |
p | 会打印与替换命令中指定的模式匹配的行。此标记通常与 -n 选项一起使用 |
w file | 将缓冲区中的内容写到指定的 file 文件中 |
& | 用正则表达式匹配的内容进行替换 |
\n | 匹配第 n 个子串,该子串之前在 pattern 中用 () 指定 |
\ | 转义(转义替换部分包含:&、\ 等) |
具体使用如例:
关于添加脚本命令a
/i
sed "2a guojia" test.sh // 将“guojia”增添在test.sh的第二行
sed "2i guojia" test.sh // 将“guojia”增添在test.sh的第二行
关于替换脚本命令c
/s
sed '3c changed' test.sh // 针对某一行,修改替换第三行的内容
sed "s/wo/ni/g" test.sh // 针对某串字符将文件中的wo全部改为ni
关于打印命令p
sed -n '/3/{ p s/line/test/p }' test.sh // 首先打印第三行内容,然后替换第三行的line为test再次打印
关于删除d
sed 'd' test.sh // 缓冲区中删除内容,并不会删除源文件中的内容
sed '3d' test.sh // 删除文件内容中的第 3 行
sed '2,3d' test.sh // 删除文件内容中的第 2、3 行
sed '/1/,/3/d' test.sh // 删除文件内容中的第 1-3行
sed '3,$d' test.sh // 删除文件内容中第 3 行开始的所有的内容
关于读文件r
sed '3r test2.txt' test.sh // 把test2文件内容哈入到test文件的第三行之后输出
关于退出文件q
sed '/number 1/{ s/number 1/number 0/;q; }' test.sh // 匹配到 number 1 时,将其替换成 number 0,然后直接退出。
我们知道sed
命令基本上只是针对单行进行操作,但是,有时我们需要对跨多行的数据执行特定操作。假设我们想要在文件中匹配的字符串mars concern
刚好位于文件内容的两行,这时使用sed命令似乎无法满足我们的需求。 幸运的是,sed 命令的设计人员已经考虑到了这种情况,并设计了对应的解决方案。sed 包含了三个可用来处理多行文本的特殊命令,分别是:
如:
sed '/first/{ N ; s/\n/ / }' test.sh // 查找含有单词 first 的那行文本,用N命令将下一行也放入缓冲区中(之间用换行符分隔),把两行当成一行来处理,然后用替换命令s将换行符替换成空格。
sed '/^$/{N ; /header/D}' test.sh // 查找空白行,用 N 命令来将下一文本行添加到缓冲区。此时如果缓冲区的内容中含有单词 header,则 D 命令会删除缓冲区中的第一行,即第一个换行符(包括换行符)之前的内容。
以上我们所提到的sed 命令处理的基本上是缓冲区中的内容,其实这里的缓冲区,应称为模式空间。但是模式空间并不是 sed 命令保存文件的唯一空间。sed 还有另一块称为保持空间的缓冲区域,它可以用来临时存储一些数据。
保持空间最直接的作用是,一旦我们将模式空间中所有的文件复制到保持空间中,就可以清空模式空间来加载其他要处理的文本内容。
相关命令如下:
命令 | 功能 |
---|---|
h | 将模式空间中的内容复制到保持空间 |
H | 将模式空间中的内容附加到保持空间 |
g | 将保持空间中的内容复制到模式空间 |
G | 将保持空间中的内容附加到模式空间 |
x | 交换模式空间和保持空间中的内容 |
大家可以思考一下以下命令的作用:
sed -n '/first/{h;p;n;p;g;p;}' test.sh
- 过滤出含有单词first的行
- h 命令将该行放到保持空间
- p 命令打印模式空间内容(即含first的那一行)
- n 命令提取数据流中的下一行(匹配到first的下一行),并将它放到模式空间
- p 命令打印模式空间的内容
- g命令将保持空间的内容(即含first的那一行)放回模式空间,替换当前文本
- p 命令打印模式空间的当前内容,即含first的那一行
通常,sed 程序的执行过程会从第一个脚本命令开始,一直执行到最后一个脚本命令。sed 提供了 b 分支命令来改变命令脚本的执行流程,其结果与结构化编程类似。语法如下:
[address]b [label]
address 参数(在最前面的内容中我们介绍过该值的两种形式)决定了哪些行的数据会触发分支命令,label 参数定义了要跳转到的位置。
我们使用下例分析以下-b的作用:
sed '{/first/b jump1 ; s/This is the/No jump on/ :jump1 s/This is the/Jump here on/}' test.sh
如果文本行中出现了 first,程序的执行会直接跳到 jump1 标签之后的脚本行。如果分支命令的模式没有匹配,sed 会继续执行所有的脚本命令。
测试命令也会更改执行流程,会根据 s 替换命令的结果,如果匹配并替换成功,则脚本的执行会跳转到指定的标签;反之,t 命令无效。测试命令使用与分支命令相同的格式:
[address]t [label]
例如我们看如下命令:
sed '{s/first/matched/ t s/This is the/No match on/ }' test.sh
即是查找模式文本first,如果匹配并替换成功,命令会直接跳过后面的替换命令;但是如果第一个没有替换成功,就执行第二个
s/This is the/No match on/