sed基本使用¶
本文目录
0x00 sed本质¶
sed的本质就是一个流式编辑器。流式编辑器用于对输入流(文件、管道、标准输入传递的数据)执行基本的文本转换操作。它有以下特点(区别于其它类型编辑器):
- 能够筛选过滤管道传递过来的文本数据
- 只能通过一次输入流,即每次的输入流只能处理一次,因此它的效率更高。例如:
(sed -n '2{p;q}';sed -n 3{p;q}) < filename命令中,第二个sed语句读取的输入流是空流
0x01 sed语法¶
sed命令的语法格式是:sed OPTIONS... [SCRIPT] [INPUTFILE...]
OPTIONS:sed命令常用选项,注意当使用-e或-f script_file选项指定SCRIPT时,[SCRIPT]参数将会被屏蔽,即sed将会将其当做输入文件处理[SCRIPT]:sed命令脚本,[SCRIPT]是第一个非选项参数,sed仅在没有使用-e或-f script_file选项指定SCRIPT时,才将其当作是script部分而非输入文件[INPUTFILE...]:sed命令输入流,[INPUTFILE...]是第二个非选项参数,如果不指定INPUTFILE或者指定的INPUTFILE为-,sed将从标准输入中读取输入流并进行过滤
将上述sed语法格式可以扩写成以下几种语法(本质是对SCRIPT部分的展开)
# 没有使用-e选项的单个表达式==单行
sed OPTIONS... Address{cmd1;cmd2;cmd3...} [INPUTFILE...] # OPTIONS没有-e/f选项,[SCRIPT]选项是Address{cmd1;cmd2;cmd3...}
# 使用-e选项的单个表达式==单行
sed OPTIONS... -e 'Address{cmd1;cmd2;cmd3...}' [INPUTFILE...] # 使用了OPTIONS中的-e选项指定SCRIPT,此时[SCRIPT]选项被屏蔽省略
# 没有使用-e选项的多个表达式==单行,分号分隔
sed OPTIONS... Address1{cmd1;cmd2;cmd3};Address2{cmd1;cmd2;cmd3}... [INPUTFILE...]
# 使用-e选项的多个表达式==单行,空格分隔
sed OPTIONS... -e 'Address1{cmd1;cmd2;cmd3}' -e 'Address2{cmd1;cmd2;cmd3}' ... [INPUTFILE...]
# 多个表达式==分行
sed OPTIONS... Address1{
cmd1
cmd2
cmd3
}
Address2{
cmd1
cmd2
cmd3
}
[INPUTFILE...]
# 使用-f选项指定SCRIPT脚本文件
sed OPTIONS... -f test.sed [INPUTFILE...] # 使用了OPTIONS中的-f选项指定SCRIPT脚本文件,test.sed脚本文件的内容可以如下所示
#!/usr/bin/sed -f
#注释行
Address1{cmd1;cmd2...}
Address2{cmd1;cmd2...}
......
0x02 sed实现机制¶
sed实现机制可以使用下列编程结构来描述
for (line=1;line<=last_line_num;++line)
do
read $line to pattern_space;
while pattern_space is not null
do
if Address1;then execute cmd1 in SCRIPT;
if Address2;then execute cmd2 in SCRIPT;
if Address3;then execute cmd3 in SCRIPT;
……
auto_print;
remove_pattern_space;
done
done
sed在对输入流进行处理时,维护了两个数据缓冲空间(这两个空间初始时都为空)
- 一直处于活动状态的
模式空间(pattern space) - 辅助性的
保持空间(hold space)
实现sed机制的编程结构中包含两个循环
sed循环的处理流程是
- (1)sed读取输入流(文件、管道、标准输入)中的一行,移除该行的尾随换行符,并将其放入到
模式空间(pattern space)中,同时将此行行号通过sed行号计数器记录在内存中 - (2)执行SCRIPT循环处理
模式空间(pattern space)中读入的行内容 - (3)跳出SCRIPT循环后返回第一步操作,继续读取输入流的下一行,直到处理完输入流的最后一行才退出
sed循环,sed处理完毕
SCRIPT循环的处理流程是
- (1)判断
模式空间(pattern space)是否为空,如果为空,则跳出SCRIPT循环;如果不为空,就执行下面操作 - (2)如果
模式空间(pattern space)中的内容能够匹配Address1,则执行Address1对应的cmd1对内容进行处理;否则不执行cmd1 - (3)如果
模式空间(pattern space)中的内容能够匹配Address2,则执行Address2对应的cmd2对内容进行处理;否则不执行cmd2 - …
- (4)当判断执行完所有的
cmd后,auto_print会自动输出模式空间(pattern space)中的内容到标准输出流或定向流中,并添加尾随的换行符 - (5)最后
remove_pattern_space会清空模式空间(pattern space)中的内容,并返回第一步操作
需要注意的是
SCRIPT循环中的2/3步对应着我们sed脚本部分(即语法格式中的SCRIPT),可以根据需要进行修改SCRIPT循环中的4/5步自动输出和清空模式空间内容,这两个操作每次SCRIPT循环都会默认自动执行,但是有些操作命令或选项可以改变这两个操作行为,使其输出总是输出空内容或无法输出或无法清空模式空间等D命令会进入多行模式,使得SCRIPT循环结束时将数据锁在模式空间(pattern space)中不输出也不清空,并且在当前SCRIPT循环还没结束时就强行进入下一轮SCRIPT循环,其实就相当 于在上面的while循环结构中加上了continue关键字d命令可以直接跳出SCRIPT循环进入下一个sed循环,就像是在while循环中加上了break一样q和Q命令可以直接退出sed循环,就像是在while循环中加上了exit一样
0x03 sed常用选项¶
sed命令的常用OPTIONS选项有
--help:输出sed命令行的简单帮助信息并退出,也可以使用info sed命令查看其帮助信息,info文档更全面详细点-n/--quiet/--silent:默认情况下,sed将在每轮SCRIPT循环结束时自动输出模式空间中的内容。使用该选项后可以使得这次自动输出动作输出空内容。注意,该选项是输出空内容而不是禁用输出动作,前者有输出流只是输出空流,后者则没有输出流;虽然两者的结果都是不输出任何内容,但在有些依赖于输出动作和输出流的地方,它们的区别是很大的。这种情况下,只有显式通过p命令来产生对应的输出-e SCRIPT/--expression=SCRIPT:SCRIPT是一个包含sed命令的表达式,-e选项就是向SCRIPT中添加命令的。可以省略-e选项,但如果命令行容易产生歧义,则使用-e选项可明确说明这部分是SCRIPT中的命令。另外,如果一个-e选项不方便描述所需命令集合时,可以指定多个-e选项-f SCRIPT-FILE/--file=SCRIPT-FILE:指定包含sed命令集合的SCRIPT文件(即将-e选项后面的SCRIPT表达式写入文件中),让sed根据SCRIPT文件中的命令集处理输入流-i[SUFFIX]/--in-place[=SUFFIX]- 该选项指定要将sed的输出结果保存(以覆盖的方式)到当前编辑的文件中。该项是通过创建一个临时文件并将输出写入到该临时文件,最后重命名为源文件来实现的。该选项隐含了
-s选项 - 当处理完当前输入流后,临时文件被重命名为源文件的名称,如果没有提供
SUFFIX,源文件被覆盖,且不会生成备份文件;如果提供了SUFFIX,则在重命名临时文件之前,先使用该SUFFIX修改源文件名,从而生成一个备份文件(例如sed -i'.log' SCRIPT a.txt将生成两个文件a.txt和a.txt.log,前者是sed修改后的文件,a.txt.log是源a.txt的备份文件) - 注意:如果
SUFFIX不包含符号*,将SUFFIX添加到原文件名的后面当作备份文件的后缀;如果SUFFIX中包含了一个或多个字符*,则每个*都替换为原文件名;这使得可以为备份文件添加一个前缀,而不是后缀,甚至可以将此备份文件放在在其他已存在的目录下
- 该选项指定要将sed的输出结果保存(以覆盖的方式)到当前编辑的文件中。该项是通过创建一个临时文件并将输出写入到该临时文件,最后重命名为源文件来实现的。该选项隐含了
-r/--regexp-extended:使用扩展正则表达式,而不是使用默认的基础正则表达式;sed所支持的扩展正则表达式和egrep一样,使用扩展正则表达式显得更简洁,因为有些元字符不用再使用反斜线\,但这是GNU扩展功能,因此应避免在可移植性脚本中使用-s/--separate:默认情况下,如果为sed指定了多个输入文件,例如sed OPTIONS SCRIPT file1 file2 file3,则多个文件会被sed当作一个长的输入流处理,也就是说所有文件被当成一个大文件进行处理。指定该选项后,sed将认为命令行中给定的每个文件都是独立的输入流;既然是独立的输入流,范围定界(如/abc/,/def/)就无法跨越多个文件进行匹配,行号也会在处理每个文件时重置,$代表的也将是每个文件的最后一行-l N/--line-length=N:为l命令指定默认的换行长度。N=0意味着完全不换行的长行,如果不指定,则70个字符就换行--follow-symlinks:该选项只在支持符号连接的操作系统上生效,且只有指定了-i选项时才生效。指定该选项后,如果sed命令行中指定的输入文件是一个符号连接,则sed将对该符号链接的目标文件进行处理。默认情况下,禁用该选项,因此不会修改链接的源文件-u/--unbuffered:使用尽量少的空间缓冲输入和输出行;该选项在某些情况下尤为有用,例如输入流的来源是tail -f时,指定该选项将可以尽快返回输出结果-z/--null-data/--zero-terminated:以空串符号\0而不是换行符\n作为输入流的行分隔符