sed
概述
参考:
sed 是一种新型的,非交互式的编辑器。它能执行与编辑器 vi 相同的编辑任务。
sed 是一种 stream editor(流编辑器),逐行处理文件(或输入),并将结果发送到标准输出。处理时,把当前处理的行存储在临时缓冲区中,称为 pattern space( 模式空间),接着用 sed 命令处理缓冲区中的内容,处理完成后,把缓冲区的内容送往屏幕。然后读入下行,执行下一个循环。如果没有使诸如‘D’的特殊命令,那会在两个循环之间清空模式空间,但不会清空保留空间。这样不断重复,直到文件末尾。文件内容并没有改变,除非你使用重定向存储输出。
功能:主要用来自动编辑一个或多个文件,简化对文件的反复操作,编写转换程序等。

sed 工作原理
sed 实际上是一个循环结构,该循环用来对输入给 sed 文本的每一行执行下列操作:
- sed 从输入内容中读取一行,删除任何尾随的换行符,并将该行保存到 模式空间 中。
- 对模式空间中的内容,执行 COMMAND。执行之前需要根据 ADDR(行定位),验证模式空间中的行是否符合 ADDR 中给定的条件。
- 只有符合条件的,COMMAND 才会执行
- 上一步完成后,模式空间中的内容会打印到标准输出中。如果删除了末尾的换行符,则会添加回去。(如果使用了 -n 选项,则不会将模式空间中的行输出)
- 然后回到循环体的开头,继续处理输入内容的下一行
除非有特殊命令(例如“d 使用’),则在两个循环之间删除模式空间。另一方面,保持空间可在周期之间保持其数据(请参见命令’H’,‘H’,‘X’,‘G’,‘G’在两个缓冲区之间移动数据)
Syntax(语法)
sed [OPTIONS] SCRIPT FILE(s)
OPTIONS
- -e, –expression=<SCRIPT> # 以选项中的指定的 SCRIPT 来处理输入的文本文件,常用来在一行命令中,执行两个 sed SCRIPT
- -f, –file=<SCRIPT> # 以选项中指定的 SCRIPT 文件来处理输入的文本文件,把 sed 相关命令写进文件里,直接引用该文件中的命令进行操作
- -i # 直接编辑原文件,sed 操作的内容不输出到屏幕,直接更改文件内容
- -n, –quiet, -silent # 禁止模式空间中的内容在标准输出中打印
- 通常与 p 命令一同使用,用来仅显示 sed 操作的行。
- -r, –regexp-extended # 允许在 SCRIPT 中使用扩展的正则表达式。如果在 SCRIPT 中使用正则,且不使用该选项,运行就会报错
SCRIPT
SCRIPT 是 sed 在处理文本时主要依赖的部分,脚本包含多个部分,至少要具有一个 COMMAND
SCRIPT 语法:[ADDR]COMMAND[OPTIONS]
- ADDR# 行定位,全称 Addresses。用于确定 sed 当前操作的文本需要处理哪些行。
- 如果指定了 ADDR ,则 COMMAND 仅对被定位的行执行操作。
- ADDR 可以是单个行号、通过 pattern(正则表达式) 来匹配指定的行、通过 X,Y 来匹配一个范围内的行
- COMMAND # 用于执行通过 行定位 匹配到的行的操作。是添加内容、还是替换内容、还是删除内容等等
- OPTIONS # 选项仅在 COMMAND 有可用的 OPTIONS 时才有用。比如 s 命令具有多个 OPTIONS
Note:行定位与 COMMAND 不分先后,不分左右,不同的 COMMAND,会出现在 SCRIPT 不同的位置
定界符
一个复杂的 SCRIPT,需要定界符来区分语法格式中每一部分。在 sed 中可以用任意字符作为定界符。sed 会自动将第一个出现的非命令字符作为定界符。一般情况定界符使用 / 。示例如下:
- sed ’s:test:TEXT:g’ file
- sed ’s|test|TEXT|g’ file
上面的示例通过定界符,区分了 COMMAND、正则表达式、要替换的内容、COMMAND 对应的 flag 定界符出现在样式内部时,需要进行转义:
- sed ’s//bin//usr/local/bin/g’ file
ADDR(行定位)
sed 工具将会更具 ADDR 来决定在哪一行或哪些行执行命令,比如下面的示例表示:仅在第 144 行将字符串 hello 替换为 world
sed '144s/hello/world/' input.txt > output.txt
ADDR 可以通过多种方式进行行定位: 一、使用数值定位行
- NUMBER # 使用行号 NUMBER,来定位指定的行
- $ # 这个符号与输入的最后一个文件的最后一行匹配,或者在指定-i 或-s 选项时与每个文件的最后一行匹配。
- first~step # 从 first 行开始,每隔 step 的行,被定位
EXAMPLE:
- sed -n 10p passwd # 输出 passwd 文件中的第 10 行
- sed -n $p passwd # 输出 passwd 文件中最后一行
- sed -n 1~5p passwd # 输出 passwd 文件中第一行、第六行、第十一行….以此类推
二、使用 RegExp(正则表达式) 定位行 Note:通过正则表达式来匹配指定的行,正则表达式两边需要添加定界符
- /RegExp/ # 根据 RegExp 匹配到内容,来定位包含这些内容的行
- /RegExp/I # 进行正则匹配时,不区分大小写
- /RegExp/M # 正则表达式匹配的 M 修饰符是 GNU sed 扩展,它指示 GNU sed 在多行模式下匹配正则表达式
EXAMPLE
- sed -n /root/p passwd # 输出 passwd 文件中所有带 root 字符的行
三、定位一个范围内的行
- NUM1,NUM2 # 使用行号定位 NUM1 到 NUM2 的所有行
- NUM,+N # 定位 NUM1 行及其后两行
- NUM,~N # 匹配 NUM1 和 NUM1 之后的行,直到行号是 N 的倍数的下一行为止。以下命令从第 6 行开始打印,直到下一行是 4 的倍数(即第 8 行):
- seq 10 | sed -n ‘6,~4p’ # 输出 6 7 8 行
- 注意:任意 NUM 可以 使用 RegExp 代替,i.e.通过正则来匹配开始行或结束行
- /RegExp1/,/RegExp2/ # 使用正则,定位 pattern1 匹配到的行,到 pattern2 匹配到的行,这两行中间的所有行
EXAMPLE
- sed -n 1,5p passwd # 输出 passwd 文件中的第一行到第五行
- sed -n /root/,/sshd/p passwd # 输出带有 root 的行,到 带有 sshd 的行,中间的所有行
- sed -n /root/,+2p /etc/passwd # 输出带有 root 的行,以及带有 root 行下面的 2 行
COMMAND(操作行为)
a <TEXT> # 在匹配行的下一行插入 TEXT
i <TEXT> # 在匹配行的上一行插入 TEXT
a\ <TEXT> # 在当前行下面插入 TEXT。
i\ <TEXT> # 在当前行上面插入 TEXT。
c\ <TEXT> # 把选定的行改为新的 TEXT。
d # 删除,删除选择的行。
D # 删除模板块的第一行。
- 删除命令用于删除匹配的行,而且删除命令还会改变 sed 脚本中命令的执行操作顺序,因为匹配的行一旦被删除,模式空间将变为“空”,自然不会再执行哪个 sed 脚本后续的命令。删除命令会导致读取新的输入行(下一行),而 sed 脚本中的命令则从头开始执行。需要注意的是删除时是删除整行,而不是删除匹配的内容(如要删除匹配的内容,可以使用替换)。
s/RegExp/REPLACEMENT/FLAGS # 在已经定位的每行中,将 RegExp 匹配到的内容,替换成 REPLACEMENT
h # 拷贝模板块的内容到内存中的缓冲区。
H # 追加模板块的内容到内存中的缓冲区。
g # 获得内存缓冲区的内容,并替代当前模板块中的文本。
G # 获得内存缓冲区的内容,并追加到当前模板块文本的后面。
l # 列表不能打印字符的清单。
L # 同 l,不显示非打印字符
n # 读取下一个输入行,用下一个命令处理新的行而不是用第一个命令。
N # 追加下一个输入行到模式空间中,并在二行间嵌入一个新行,改变当前行号码。
p# 打印模式空间中执行了 COMMAND 的内容
P # 打印模板块的第一行。
q # 退出 Sed。
b lable 分支到脚本中带有标记的地方,如果分支不存在则分支到脚本的末尾。
r file 从 file 中读行。
t label if 分支,从最后一行开始,条件一旦满足或者 T,t 命令,将导致分支到带有标号的命令处,或者到脚本的末尾。
T label 错误分支,从最后一行开始,一旦发生错误或者 T,t 命令,将导致分支到带有标号的命令处,或者到脚本的末尾。
w file 写并追加模板块到 file 末尾。
W file 写并追加模板块的第一行到 file 末尾。
! # 表示后面的命令对所有没有被定位到的行发生作用。i.e.对行定位操作匹配到的行取反。
= 打印当前行号码。
把注释扩展到下一个换行符以前
特殊 COMMAND
替换指令(S, SUBSTITUTION)
指令格式:[address]s/pattern/replacement/flags
- address # 操作地址
- s # 替换指令
- pattern # 匹配需要替换的内容
- replacement # 为替换的内容
- flags # 标记可以是如下内容:
- n # 1 - 512 之间的数字,表示对模式空间中指定模式的第 n 次出现进行替换。如一行中有 3 个 A,而只想替换第二个 A。
- g # 对模式空间的所有匹配进行全局更改。没有 g 则只有第一次匹配被替换。如一行中有 3 个 A,则仅替换第一个 A。
- p # 打印模式空间的内容,即表示打印行。与-n 选项一起使用可以只打印匹配的行。
- w file # 将模式空间的内容写到文件 file 中。 即表示把行写入一个文件。
replacement 为字符串,用来替换这则表达式匹配的内容。在 replacement 部分,下列字符有特殊含义:
- & 用正则表达式匹配的内容进行替换
- \n 匹配第 n 个子串,该子串之前在 pattern 中用
\(\)指定,即正则表达式分组。 - \ 转义(转义替换部分包含:&、\等)
EXAMPLE
- set -n ’s/123/234/‘p test # 把 test 文件中的 123 替换为 234,并显示所有完成替换的行
- sed ’s/|/\n/’ FILE # 把 FILE 文件中的每个|符号变成换行符,即让一行的内容变成多行
- sed ‘:t;N;s/\n//;b t’ FILE # 把 FILE 问文件中的换行符清空,即然多行内容变为一行
- sed ’s/^[ \t]*//’ FILE # 删除行首 tab 键
- echo this is a test line | sed ’s/\w+/[&]/g’ # 将所有的单词用中括号 [] 包裹起来:
转换指令(Y)
按字符转换(Transform)的语法格式为:[address]y/yousource-chars/dest-chars/
- address 用于定位需要修改的行
- source-chars 为需要修改的字符
- dest-chars 为准备替换的字符。
EXAMPLE
- 就文件中的 china 转换为大写:
- sed ‘/china/y/abcdefghijklmnopqrstuvwxyz/ABCDEFGHIJKNOPQRSTUVWXYZ/’ file
其他
命令组合
用时候我们可能会对一个文件或者输入做连续的 sed 处理,例如:
sed ‘表达式’ | sed ‘表达式’ | sed ‘表达式’
其实,我们可以将所有的表达式用分号(;)组合起来,即:
sed ‘表达式; 表达式;表达式’
分号的含义就是将前面的处理完结果传给后边的表达式继续处理。
我们也可以对多个命令用大括号 {} 进行组合,然后作用于同一匹配地址,即:
address{commad1; command2; command3}
也可以放在多行:
address{ commad1 command2 command3}
示例,如果文件中含 test 的行,则将其下一行的 aa 替换为 bb:
sed ‘/test/{ n; s/aa/bb/; }’ file
选定行的范围
选择要处理行的范围,可以用逗号(,)来分割。例如选定所有在模板 test 和 check 所确定的范围内的行:
sed -n ‘/test/,/check/p’ file
打印从第 5 行开始到第一个包含以 test 开始的行之间的所有行:
sed -n ‘5,/^test/p’ file
对于模板 test 和 west 之间的行,每行的末尾用字符串 aaa bbb 替换:
sed ‘/test/,/west/s/$/aaa bbb/’ file
Sed 常用格式
sed 命令行常用的基本格式大致有一下三种形式:
(1)Sed [options] ‘script’ file1 file2 …
script 结构为 /PATTERN/action,PATTERN 为正则表达式,action 为要执行的动作。例如:sed ‘/[[:upper:]]/d’ binary.sh 表示删除所有的大写字母的行。script 的结构还可以是 /PATTERN1/,/PATTERN2/action,这表示从第一次被 PATTERN1 匹配到的行到第一次被 PATTERN2 匹配到的中间的所有行执行 action 动作。
这里需要注意的是,当进行字符串替换时,需要在 PATTERN 前加上 s 动作,并在末尾加上替换的范围,例如: sed ’s/abc/123/g’ 表示将匹配到的字符串 abc 替换成 123,g 表示替换所有的行。
(2)Sed [options] –f scriptfile file1 file2 …
scriptfile 表示脚本文件,即 sed 支持将要执行的操作写在文件里边,然后通过使用 -f 参数来加载文件。
(3)Sed [options] ‘ADDR1,ADDR2command’ file1 file2 …
该格式应用于以行为单位的操作,例如:
sed ’1,2d’ file
就可以将 file 的前两行删除并显示出来,但是它不会改变源文件。
Sed ‘1,2!d’ file
表示删除除第一行和第二行之外的所有行。
注: 在这种格式中的 & 表示引用前面匹配到的所有字符。并且在该种格式中可以引入分组。
示例:
$ sed ’s/bc/-&-/’ testfile
这里表示在匹配到 bc 字符两端加上字符’-’
$ sed ’s/ /-\1-\2/’ testfile
这里的 \1 和 \2 表示正则表达式的分组 1 和分组二所匹配的内容。
Sed 高级应用
正常的 Sed 数据处理流程是读取文档的一行至模式空间,然后对该行应用相应的 Sed 指令。当指令完成后输出该行并清空模式空间,一次循环读入文档的下一行数据,直至文档数据结尾。然而在真实环境中的数据可能并不会那么有规律,有时我们会把数据分多行写入文档,如:
姓名:张三邮箱:zhangsan@gmail.com姓名:李四邮箱:lisi@gmail.com
从上面的模板文件中可以看出,实际每两行位一条完整的记录,而此时如果需要用 Sed 对文档进行处理,就需要对 Sed 工作流程进行人工干预。
多行操作 Next
Next(N)指令通过读取新的输入行,并将它追加至模式空间的现有内容之后,来创建多行模式空间。模式空间的最初内容与新的输入含之间用换行符分隔。在模式空间中插入的换行符可以用 \n 匹配。
列举一个范例,范例所用样本文件如下(test.txt):
Name:HuotyMail:huoty@gmail.comName:KonghyMail:konghy@163.com
我们要做的处理是,当读入的内容与 Name 匹配时,立刻读取下一行,再输入模式空间中的内容。处理脚本如下所示(sed.sh):
#n/Name/{NL}
其中,#n 放在脚本文件中表示屏蔽自动输出,L 表示不打印非打印字符(小写 l 标识打印非打印字符),即行尾的 \n。用 sed 执行操作如下:
sed -f sed.sh test.txt
多行操作 Print
Print(p)表示仅输出多行模式空间中的第一部分直到第一个插入的 \n 换行符为止。如模式空间中的内容为 “aaa\nbbb”,则 P 只输出 aaa。
多行删除 Delete(D)
Delete 删除模式空间中直到第一个插入的换行符(\n)前的内容。由于 d 命令的作用是删除模式空间中的内容并读取新的输入行,而如果 sed 在 d 指令后还有多条命令,则余下的指令将不再执行。而返回第一条指令对新度入行进行处理。多行指令 D 则不会读入因的行,而是放回 sed 脚本的顶端,使得剩余指令继续应用于模式空间中的剩余部分内容。
Hold(h,H), Get(g,G)
Sed 还有一个称为保持空间(hold space)的缓冲区。模式空间的内容可以复制到保持空间,保持空间同样可以复制到模式空间。由一组 Sed 命令用于两者之间移动数据:
Hold(h|H) 将模式空间的内容复制或者追加到保持空间 Get(g|G) 将保持空间的内容复制或者追加到模式空间 Exchange(x) 交换保持空间与模式空间中的内容
举一个使用范例,样本文件如下(test.txt):
aaabbbcccddd
Sed 教程文件如下(sed.sh):
/aaa/{hd}/ccc/{G}
执行处理命令:
sed -f sed.sh test.txt
结果如下所示:
bbbcccaaaddd
sed{
应用示例
- 获取双引号之间的字符。假如 sed.txt 中的内容为
"bitnami "。那么下面命令会输出bitnami- sed ’s/^"(.)"./\1/’ sed.txt
- 打印 passwd 文件的内容,等效于 cat passwd 命令。
- sed -n p passwd
- 注意: 如果不加 -n,则 passwd 每行内容输出两次,因为 sed 本身的逻辑在从模式空间到标准输出一行,然后 p 命令还会再将该行输出一遍。
- 删除开头带#的行
- sed ‘/^#/d’ FILE
- 删掉空白行:
- sed ‘/^$/d’ file
- 搜索 resolv.conf 文件中,开头带有 nameserver 字符串的行,并在行首添加#
- sed ‘/^nameserver/s/^/#/’ /etc/resolv.conf
- 将 resolv.conf 文件中,具有 nameserver 关键字的行开头的 # 符号去掉。
- sed ’s/#(nameserver.*)/\1/’ /etc/resolv.conf
- 在 hostname 行的前一行添加 ${STRING} 变量中的内容。其中
STRING="\ \ \ \ \ \ labels:"- sed -i “/hostname/i${STRING}” prometheus.yml #
- 在 hostname 行的行首添加两个空格
- sed “s/hostname/ &/” prometheus.yml
- 在文件最后一行添加变量中的内容,注意 $a 前加
\符号以便让 sed 认出 $a 表示最后一行sed -i "$a${Masters\[${i}]%%=*} ${Masters\[${i}]##\*=}" /tmp/hosts#
- 在开头是 kind: Deployment 这行的下一行的下一行,添加 namespace: redis 行
sed -n '/^kind: Deployment/{N;a\ namespace: redis
p}' all-redis-operator-resources.yaml

匹配行的下 N 行替换内容
定位到包含字符串 console-agent-exporter 的行下的第 1 行,将 scrape_interval.* 替换为 scrape_interval: 180s
- sed ‘/console-agent-exporter/{n;s/scrape_interval.*/scrape_interval: 180s/;}’ prometheus.yml
定位到包含字符串 console-agent-exporter 的行下的第 2 行,将 scrape_timeout:.* 替换为 scrape_timeout: 180s
- sed ‘/console-agent-exporter/{n;n;s/scrape_timeout.*/scrape_timeout: 180s/;}’ prometheus.yml
其他
- if [[ !
grep 'web.config=' /opt/monitoring/client/docker-compose.yml]]; then sed -i ‘/web.listen-address=:9100/i\ \ \ \ - –web.config=/etc/prometheus/config_out/web-config.yml’ /opt/monitoring/client/docker-compose.yml; fi
意见反馈
这个页面对您有帮助吗?
Glad to hear it! Please tell us how we can improve.
Sorry to hear that. Please tell us how we can improve.