sed 是一个比较古老的,功能十分强大的用于文本处理的流编辑器,加上正则表达式的支持,可以进行大量的复杂的文本编辑操作。

简介

sed 全名为 stream editor,是一个流编辑器,用于处理来自文件或管道的输入流,进行基本文本的匹配及处理。

sed会一次处理一行内容。处理时,把当前处理的行存储在临时缓冲区中,成为"模式空间",接着用sed命令处理缓冲区中的内容,处理完成后,把缓冲区的内容送往屏幕。接着处理下一行,这样不断重复,直到文件末尾。文件内容并没有改变,除非你使用重定向存储输出。

sed能够对来自于管道的文本进行过滤,与其他类型编辑器相比,这是它的独特之处。

使用

使用形式:sed OPTIONS . . . [SCRIPT] [INPUTFILE . . .] :

  • OPTIONS:命令行选项
  • [SCRIPT]:操作脚本
  • [INPUTFILE . . .] :输入流来源

Linux命令行执行一条命令后一般会返回一个状态码(echo $?),sed返回的状态码有:

  • 0:成功完成
  • 1:命令无效、语法无效、正则表达式无效或者在”--posix“下执行了GNU sed扩展的命令。
  • 2:命令行上指定的一个或者多个输入文件不能打开(例如,文件找不到,或者无权限读取,被拒绝),程序会继续处理其他文件。
  • 4:出现一个I/O错误,或运行时发生严重的操作错误,GNU sed立即中止程序。

操作脚本中的行操作命令

  1. a 命令——添加新行

    在匹配的行下面添加新行

  2. i 命令——插入新行

    在匹配的行上面插入新行

  3. c 命令——行替换

    替换指定范围的行的内容

  4. d 命令——删除

    删除指定范围

  5. p 命令——打印

    打印指定范围的内容

  6. = 命令——打印行号

    打印指定范围的行号

  7. s 命令——正则替换

    指定范围内容进行正则替换,格式为: s/正则表达式/要替换的内容/

    s 命令最后跟个 g 表示替换该行所有匹配

    不加 g 的 s 只能替换每一行匹配到的第一个

    sed '4,8s/\(line\)\([[:digit:]]\+\)/\2 - \1/' a.txt
    # 4,8 表示从第 4 行到第 8 行
    # \(line\)\([[:digit:]]\+\) 是正则表达式
    # \1 表示正则表达式中第一个括号匹配的结果
    # \2 表示正则表达式中第二个括号匹配的结果
    
    # 可以加 -r 参数开启扩展正则表达式,写成等价形式
    sed -r '4,8s/(line)([[:digit:]]+)/\2 - \1/' a.txt
    
  8. y 命令——字符映射替换

  9. r 命令——行替换,替换内容为文件内容

操作脚本中的其它命令

  1. {} ——脚本块

    在大括号内用分号隔开命令,可以实现执行多个命令,多个命令范围相同,则可以省略相同匹配后面的范围指定

    脚本块可以嵌套,嵌套时范围指定不同,则会取交集

  2. b ——标签跳转

    跳转到用冒号开头表示的标签,当标签在最后时,可以省略,而且当 b 命令指定的标签不存在时,会自动跳转到最后

    如果标签在前可能造成死循环,需要注意指定行

  3. t ——条件正则跳转

    如果前一条命令执行成功,则跳转到用冒号开头表示的标签

  4. 空间交换命令

    **模式空间:**sed 命令默认是一行一行处理的,每读取到一行,会放到模式空间里,然后执行脚本来处理模式空间的内容,处理完后会清空模式空间,并且读取下一行继续处理,如此循环直到行尾。模式空间相当于专门用于 sed 处理的字符串缓冲区。

    **保持空间:**默认的 sed 是不会操作保持空间的,保持空间是专门为用户提供的空间,这几个命令可以操作保持空间,来实现更复杂的功能。

    **h:**把模式空间内容覆盖到保持空间中 **H:**把模式空间内容追加到保持空间中 **g:**把保持空间内容覆盖到模式空间中 **G:**把保持空间内容追加到模式空间中 **x:**交换模式空间与保持空间的内容

  5. 模式空间命令

    有了模式空间的概念后,可以重新理解一下前面 p、d、n 等命令的本质。

    **p:**打印当前模式空间所有内容,追加到默认输出之后。

    **P:**打印当前模式空间开端至\n的内容,并追加到默认输出之前。Sed并不对每行末尾\n进行处理,但是对N命令追加的行间\n进行处理,因为此时sed将两行看做一行。

    **n:**命令简单来说就是提前读取下一行,覆盖模型空间前一行,然后执行后续命令。然后再读取新行,对新读取的内容重头执行sed。

    **N:**命令简单来说就是追加下一行到模式空间,同时将两行看做一行,但是两行之间依然含有\n换行符,然后执行后续命令。然后再读取新行,对新读取的内容重头执行sed。此时,新读取的行会覆盖之前的行(之前的两行已经合并为一行)。

    **d:**命令是删除当前模式空间内容(不再传至标准输出), 并放弃之后的命令,并对新读取的内容,重头执行sed。

    **D:**命令是删除当前模式空间开端至\n的内容(不在传至标准输出), 放弃之后的命令,但是对剩余模式空间重新执行sed。

操作脚本中的范围指定

sed命令可以不带地址范围指定,在这种情况下,将对所有输入行执行该命令。

  1. ,——范围分隔符
  2. +——到接下来几行
  3. ,~——行数倍数匹配,到第一次倍数匹配的位置
  4. ~——步进
  5. $——最后一行
  6. !——范围取反
  7. /[正则匹配式]/——正则表达式范围

运行

$ for a in $(seq 1 1 6);do echo modao$a;done > a.txt
$ cat a.txt
modao1
modao2
modao3
modao4
modao5
modao6
$ ls
a.txt
$ cat a.txt
modao1
modao2
modao3
modao4
modao5
modao6
$ sed '1,3a newmodao' a.txt
modao1
newmodao
modao2
newmodao
modao3
newmodao
modao4
modao5
modao6
$ sed '1,3i newmodao' a.txt
newmodao
modao1
newmodao
modao2
newmodao
modao3
modao4
modao5
modao6
$ sed '1,3c newmodao' a.txt
newmodao
modao4
modao5
modao6
$ sed '1,3d' a.txt
modao4
modao5
modao6
$ sed '1,3p' a.txt
modao1
modao1
modao2
modao2
modao3
modao3
modao4
modao5
modao6
$ sed -n '1,3p' a.txt
modao1
modao2
modao3
$ sed -n '1,3=' a.txt
1
2
3
$ sed '1,3=' a.txt
1
modao1
2
modao2
3
modao3
modao4
modao5
modao6
$ sed '1,3s/modao/regex/' a.txt
regex1
regex2
regex3
modao4
modao5
modao6
$ sed -n '1,3s/modao/regex/' a.txt
$ sed  '1,3y/modao/regex/' a.txt
regee1
regee2
regee3
modao4
modao5
modao6
$ sed -n '1,3{y/modao/regex/;p}' a.txt
regee1
regee2
regee3
$ sed -n '1,3{y/modao/regex/;p}' a.txt > b.txt
$ cat b.txt
regee1
regee2
regee3
$ sed -n '3,$rb.txt' a.txt
regee1
regee2
regee3
regee1
regee2
regee3
regee1
regee2
regee3
regee1
regee2
regee3
$ sed '3rb.txt' a.txt
modao1
modao2
modao3
regee1
regee2
regee3
modao4
modao5
modao6
$ sed -n '3rb.txt' a.txt
regee1
regee2
regee3
$ sed '/modao4/bend;p;:end' a.txt
modao1
modao1
modao2
modao2
modao3
modao3
modao4
modao5
modao5
modao6
modao6
$ sed -n '/modao4/bend;p;:end' a.txt
modao1
modao2
modao3
modao5
modao6
$ sed -n '/modao4/p;tend;s/modao/modao233/;:end' a.txt
modao4
$ sed  '/modao4/d;tend;s/modao/modao233/;:end' a.txt
modao2331
modao2332
modao2333
modao2335
modao2336
$ sed '1h;2H;3x;4H;5H;6G' a.txt
modao1
modao2
modao1
modao2
modao4
modao5
modao6
modao3
modao4
modao5
$ sed 'n;p' a.txt
modao1
modao2
modao2
modao3
modao4
modao4
modao5
modao6
modao6
$ sed -n 'n;p' a.txt
modao2
modao4
modao6
$ sed -n 'N;P' a.txt
modao1
modao3
modao5
$ sed -n '1,3p' a.txt
modao1
modao2
modao3
$ sed -n '1,+3p' a.txt
modao1
modao2
modao3
modao4
$ sed -n '1,~3p' a.txt
modao1
modao2
modao3
$ sed -n '1~3p' a.txt
modao1
modao4
$ sed -n '1,$p' a.txt
modao1
modao2
modao3
modao4
modao5
modao6
$ sed -n '3,$!p' a.txt
modao1
modao2

参考

  1. GNU sed 4.5 版参考文档全文翻译 各命令和随带20个示例详细解析
  2. sed 命令从入门到精通
  3. sed(1) - Linux man page
  4. 菜鸟教程 —— Linux sed 命令
  5. 肖邦linux —— sed入门详解教程
  6. DataCareer —— Sed命令n,N,d,D,p,P,h,H,g,G,x解析