https://zhuanlan.zhihu.com/p/145661854

sed是什么

sed是一个流编辑器!什么是流编辑器?将文件或标准输入的内容作为编辑的对象,对其按照需求进行修改。

pattern space是什么?在流编辑中有pattern space的概念,翻译为:模式空间。简单理解就是一个缓冲区,sed从输入流中一行一行的取出内容放到这个缓冲区中按照SCRIPT(脚本)进行处理。

sed的总体结构

sed [OPTION]... {script-only-if-no-other-script} [input-file]...

[OPTION]... 为一系列可选的sed命令选项,省略号代表可以为一个或多个。 下面列举出几个常用的选项,全部的选项可以在man文档中查看。

-n
--quiet
--silent

默认情况下在对模式空间中内容进行处理完之后打印到屏幕然后取下一行进行处理。如果加了这些选项,在处理后只有在SCRIPT(脚本)中明确指定了p的时候才会输出当前模式空间的内容。

-e SCRIPT
--expression=SCRIPT

添加sed commands(sed命令)到sed SCRIPT(脚本)中。为什么说是添加?因为可以多次用该选项,添加多个命令。脚本的语法下面将会详细讲解,当脚本中包含空格时需要将脚本应单引号包含。

-f SCRIPT-FILE
--file=SCRIPT-FILE

将文件中的内容作为脚本,添加到当前脚本中,可以与-e共存。文件中脚本的语法与-e后的脚本语法一致。

-i[SUFFIX]
--in-place[=SUFFIX]

默认对模式空间中的内容进行修改不会影响原文件的内容,如果添加该选项表示就地编辑,会直接改动原文件内容。其中SUFFIX(后缀)是可选的,如果设置了的话,在改动原文件之前会将其以SUFFIX为文件名后缀备份一份。例如-i".bak" sample.txt会在处理前将sample.txt备份为sample.txt.bak 。

--follow-symlinks

在使用-i选项进行就地修改的时候,如果处理的文件名为一个符号链接,如果不加该选项链接到的实际文件将无法实现就地修改。

-E
-r
--regexp-extended

使用扩展正则(ERE),默认使用基础正则。关于正则这一篇就够了:http://deerchao.net/tutorials/regex/regex.htm

-s
--separate

当输入为多个文件时默认将其合并为一个流,使用该选项可以将其分开单独处理。

{script-only-if-no-other-script}

当-e, –expression, -f, or –file这些选项都没有指定时,在该位置(也就是在可识别的命令选项后,输入文件前的位置)的内容被作为sed SCRIPT(脚本)。

[input-file]...

要处理的文本,可以为文件、标准输入、管道传入的文本(其实也是标准输入)。

sed SCRIPT(脚本)

sed SCRIPT是sed的核心,SCRIPT由一系列的sed commands(sed命令)组成,使用-e,-f等选项将一系列的sed命令添加到脚本当中。在循环处理的过程中,对模式空间的内容使用脚本进行处理作为结果。

commands(sed命令)

sed命令语法:

[addr]X[options]

addr是一个可选的能否标识行的地址,可以是一个单独的方号、正则、行范围。

  • 单独一个数字标识行号。
  • 3,5表示3-5行。
  • /^#define/ 表示以#define开头的行。
  • /X$/ 表示以X结尾的行。
  • $表示最后一行。 X[options]是一个动作及其选项,该动作只对addr能够匹配的行进行处理,可选值有以下:

  • a :新增, [options]为要增加的内容,新增的内容为单独一行,在当前行的下方,如果需要增加多行,行与行之间使用\n分割。
  • c :取代, [options]为新的内容。
  • i :插入, [options]为要插入的内容,插入的内容为单独一行,在当前行的上方,同样可以使用\n实现插入多行。
  • d :删除, 不需要[options]。
  • p :列印,不需要[options],将当前模式空间的内容打印出来,通常与参数 sed -n配合使用。
  • s :取代,最复杂的一个命令,[options]为正则表达式/REGEXP/REPLACEMENT/[FLAGS],例如:s/old/new/g表示将old换为new,g表示进行全局替换,默认为替换第一处。/old/new/g为s的option。
  • REGEXP
  • 正则表达式,匹配的内容会被REPLACEMENT替换。
  • REPLACEMENT
  • 字符串,直接替换
  • \N N可以为1~9, 引用匹配分组的内容。
    sed -e 's/#\(Port.+\)/\1/g' /etc/ssh/sshd_config
    sed -r -e 's/#(Port.+)/\1/g' /etc/ssh/sshd_config
    上面的两行等价将以#PORT开始的行#去掉,使用-r选项能够避免使用()
  • & 引用整个匹配内容
    sed -e s/^Port/#&/g /etc/ssh/sshd_config
    匹配以Port开头的行,并在前面加上#。
  • \L 将后面的内容转为小写,直到遇到\U或\E结束
  • \l 将后面的一个字符转为小写
  • \U 将后面的内容转为大写,直到遇到\L或\E结束
  • \u 将后面的一个字符转为大写
  • \E 结束\L,\U的转换
    sed -r -e 's/(\b[^\s])/\u\1/g' /etc/ssh/sshd_config
    将所有单词首字母大写。

  • FLAGS

  • g 全局替换
  • p 打印
  • = 打印行号

  • y :转换,[options]为转换字典/src/dst/,将出现的每个src中的字符替换为dst中相应的字符,y/abc#/ABC%/a->A,b->B,c->C,#->%

  • q :退出,[options]为返回值,退出后直接结束输入流的处理。

多个命令可以使用;进行分割,但是a,c,i这三个后面无法使用;再接其它命令,这也就是说如果使用多个命令这三个必须放在最后,例如:/^abc/p;a newline将abc开始的行打印,并在其后添加一行。

实例

如果你已经完全掌握了上面的内容,下面的实例已经不需要看了,实例可以千变万化但是万变不离其中。当然如果你理解上面的讲解有困难可以结合实例再回到上面去看!

# 打印1-3行
sed -n -e '1,3p' sample.txt
# 删除1-3行
sed -n -e '1,3d' sample.txt
# 打印出abc开始的行
sed -n -e '/^abc/p;a newline' sample.txt
# 在所有行前加#
sed -e 's/^/#/g' sample.txt
# 在所有非#开头的行加#
sed -e 's/^[^#]/#/g' sed_sample.txt
# 将所有字母大写
sed -r -e 's/(.*)/\U\1/g' /etc/ssh/sshd_config
# 将所有单词首字母大写
sed -r  -e 's/(\b[^\s])/\u\1/g' /etc/ssh/sshd_config
# 删除所有#开头的行
sed -r -e '/^#/d' /etc/ssh/sshd_config
# 将sshd_config中的#PasswordAuthentication yes去除注释,并将yes改为no
sed -n -r -e 's/^.{0,1}(PasswordAuthentication ).{2,3}$/\1no/gp' /etc/ssh/sshd_config
# 就地修改
sed  -i -r -e 's/^.{0,1}(PasswordAuthentication ).{2,3}$/\1no/g' /etc/ssh/sshd_config

最后

还有哪些没有提到?

commands(sed命令)还有很多,具体参看info sed,有了本文的基础再看info就so easy了。

总结:要想真正的掌握某个工具的使用必须先从结构上认识这个工具,了解工具的原理,照葫芦画瓢的方法来学习会把你累死的,学了在实际中你也很难直接用。