sed基本使用

本文目录

0x00 sed本质

sed的本质就是一个流式编辑器。流式编辑器用于对输入流(文件、管道、标准输入传递的数据)执行基本的文本转换操作。它有以下特点(区别于其它类型编辑器):

  • 能够筛选过滤管道传递过来的文本数据
  • 只能通过一次输入流,即每次的输入流只能处理一次,因此它的效率更高。例如:(sed -n '2{p;q}';sed -n 3{p;q}) < filename命令中,第二个sed语句读取的输入流是空流

0x01 sed语法

sed命令的语法格式是:sed OPTIONS... [SCRIPT] [INPUTFILE...]

  • OPTIONSsed命令常用选项,注意当使用-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一样
    • qQ命令可以直接退出sed循环,就像是在while循环中加上了exit一样

0x03 sed常用选项

sed命令的常用OPTIONS选项有

  • --help:输出sed命令行的简单帮助信息并退出,也可以使用info sed命令查看其帮助信息,info文档更全面详细点

  • -n/--quiet/--silent:默认情况下,sed将在每轮SCRIPT循环结束时自动输出模式空间中的内容。使用该选项后可以使得这次自动输出动作输出空内容。注意,该选项是输出空内容而不是禁用输出动作,前者有输出流只是输出空流,后者则没有输出流;虽然两者的结果都是不输出任何内容,但在有些依赖于输出动作和输出流的地方,它们的区别是很大的。这种情况下,只有显式通过p命令来产生对应的输出

  • -e SCRIPT/--expression=SCRIPTSCRIPT是一个包含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.txta.txt.log,前者是sed修改后的文件,a.txt.log源a.txt的备份文件)
    • 注意:如果SUFFIX不包含符号*,将SUFFIX添加到原文件名的后面当作备份文件的后缀;如果SUFFIX中包含了一个或多个字符*,则每个*都替换为原文件名;这使得可以为备份文件添加一个前缀,而不是后缀,甚至可以将此备份文件放在在其他已存在的目录下
  • -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作为输入流的行分隔符

0x04 sed程序

0x0400 sed程序之范围定界

0x0401 sed程序之操作命令

0x05 sed脚本

0x06 sed输入流

0x06 sed应用