【学习笔记】sed 命令及参数详解

sed 命令及参数详解

标签:Sed


文章目录

  • sed 命令及参数详解
  • 一、简介
  • 二、基本用法
    • 2.1. 三种方式
    • 2.2. 常用选项
    • 2.3. 命令体的组成
      • 2.3.1. 定位文本部分
      • 2.3.2. 编辑命令部分
    • 2.4. 参数解释
      • 2.4.1. 定位文本
        • 2.4.1.1. 行匹配
          • (1) -n 与 p
          • (2) -e 、 =
          • (3)-f 选项
        • 2.4.1.2. 行匹配的特殊表达
      • 2.4.2. 编辑命令
        • 2.4.2.1. 处理文本
          • (1)a命令--追加文本
          • (2)i命令--插入文本
          • (3)c命令--整行替换
          • (4)d命令--删除文本
          • (5)s命令--替换文本(最常用)
          • (6)w命令--写入新文件
        • (7)r命令--从文件中读入文本
          • (8)q命令--退出命令
          • (9)y命令--字符映射替换
          • (10){} -- 命令组
          • (11)n命令--处理匹配行的下一行
      • 2.4.2.2. 编辑命令的特殊表示
  • 三、高级用法
    • 3.1. 段落操作
      • 3.1.1. :a;N;$!ba --全文预读
      • 3.1.2. :a;N;/\n\$/!{$!ba} -- 以空行分割按段预读
    • 参考

一、简介

sed - stream editor for filtering and transforming text.
sed,全称stream editor,是一种流编辑器,用于过滤和转换文本。

          sed 一次只读取一行文本到缓冲区,然后读取命令,对此行进行编辑,然后读取下一行,重复此过程直到结束。

特点:

  • 非常高效

因为不需要一次性将文本全部加载出来。

适用场合:

  • 大文件编辑

  • 复杂的编辑命令

  • 单次扫描文件,多个编辑命令

sed 对缓冲区进行编辑,不直接编辑原始文件,所以需要重定向保存更改结果。

二、基本用法

2.1. 三种方式

  • 命令行方式

  • sed 脚本方式 (与sed -f一起使用)

  • shell 脚本方式

2.2. 常用选项

  • -n,suppress automatic printing of pattern space #抑制pattern space内容的自动打印,常与p连用只显示sed动作生效的行(p的作用是打印patter space里的内容)

  • -i,edit files in place (makes backup if SUFFIX supplied) #直接修改文件,i后直接加上后缀可以备份源文件,如sed -i.bak commond,会生成一个.bak的备份文件

  • -E, -r,use extended regular expressions in the script #让sed支持扩展正则

  • -e script,add the script to the commands to be executed #如果有多段sed命令需要执行,-e用于间隔每一段sed命令

  • =,Print the current line number #打印行号

  • -f script-file,add the contents of script-file to the commands to be executed #表示调用 sed 脚本文件

2.3. 命令体的组成

  • 定位文本部分

  • 编辑命令部分

2.3.1. 定位文本部分

定位文本方法

  • x,匹配指定行号

  • $,$在正则中表示锚定行尾,在定位部分表示匹配最后一行,即末尾

  • x,y,匹配从 x 行到 y 行的内容,如果 y < x,则匹配 x

  • /pattern/,匹配包含pattern的行

  • /pattern1/pattern2/,查询包含pattern1和pattern2的行

  • /pattern/,x,从与 pattern 匹配的行到第 x 行间的所有行

  • x,/pattern/,从第 x 行到与 pattern 匹配的所有行

  • x,y!,匹配不包括 第x行 至 第y行的行

  • first~step,匹配从first开始,间隔为step的行

  • addr1,~N,匹配从addr1开始的N行,仅GUN sed支持

  • addr1,+N,匹配addr1和它后面的N行,仅GUN sed支持

  • 0,addr2,匹配从开始至addr2的行,仅GUN sed支持

2.3.2. 编辑命令部分

常用编辑命令:

  • p,打印pattern space的内容(常与-n一起用,实现只打印匹配行)

  • a\,新增, a 的后面可以接字符串,a后面的内容会追加到匹配行的下一行(可以在参数a和要添加的内容之间加上反斜杠\,能够更清晰的区分命令和要添加的内容)

  • i\,插入, 使用方法与a相同,不同的是i后面的内容会插入到匹配行的上一行(同样可以使用\分隔命令与要添加的内容)

  • c\,取代,c后面的字符串可以替换掉匹配的行(可以是n1,n2范围内的多行),可以加\

  • d,删除定位行,如/con/d(删除包含con的行)或 5d(删除第5行)

  • r filename,Append text read from filename.#从r后面的文件中读取文件内容并追加

  • w filename,Write the current pattern space to filename.

  • W filename,Write the first line of the current pattern space to filename.This is a GNU extension.

  • && 符号代表的是前面的匹配的模式。

  • {},命令组,组内命令用分号;分隔

2.4. 参数解释

2.4.1. 定位文本

2.4.1.1. 行匹配
(1) -n 与 p

  sed -n '1p' file,只输出第一行

  sed '1p' file,会先输出第一行,然后输出全部行(第一行输出两次)

  sed -n '3,6p' file,只输出 3-6 行

(2) -e 、 =

  -e,expression,表示将下一个字符串解析为 sed 命令,当只有一个命令时可省略

  =,输出匹配行行号

所以,

  sed -n '/Certificate/=' file只会输出匹配到Certificate的行到行号

  sed -n -e '/Certificate/p' -e '/Certificate/=' file会先执行第一句,输出存在Certificate的行,再(另起一行)输出此行行号

  X 注意,sed 不支持多个编辑命令合并使用,如sed -n '/Certificate/p=' file

(3)-f 选项

          -f只有调起 sed 脚本文件时才起作用。追加、插入、修改、删除、替换常常需要几条 sed 命令组合完成,如追加一行的例子可以用 sed '/Certificate/a\a new line.' file ,但如果要追加一个多行文本,就可以定义一个 sed 脚本文件append.sed内容如下:

!/bin/sed -f
/Certificate/a\nA new line.\nAnother new line.
#两个\n是换行符,表示换行

          然后执行命令./append.sed file(执行前需要先执行chmod +x append.sed给脚本文件添加执行权限)

2.4.1.2. 行匹配的特殊表达
  • $在正则中表示行尾,但在 sed 定位部分表示最后一行。如sed -n '$p' file表示只输出最后一行

  • !符号取反,即x,y!表示匹配不在 x-y 范围内的行,如sed -n '2,10!p' file表示输出 2-10 之外的行。但!不能用于模式匹配,即 /pattern/! 不可用,但有一个例外,就是d命令,/pattern/!d可以表示删除匹配行之外的其他行

  • sed 的编辑命令放在单引号内外皆可,如,sed -n '$p' file等价于sed -n '$'p file,但不推荐这样使用

2.4.2. 编辑命令

2.4.2.1. 处理文本
(1)a命令–追加文本

  a\,append,追加a后面的内容到匹配行的下一行(可以使用\来区分命令和要添加的内容)
  如/1$/a\con(在以1结尾的行的下一行添加con),演示结果如下:

[root@localhost~] #sed -i '/1$/acon' file    #\可加可不加
13591641234 
13591641231
con
13591641232
13591641235
(2)i命令–插入文本

  i\,insert,用法和\a追加文本一致,只不过是在匹配行的行前添加文本

  如2i\con(在第2行前面插入con),演示结果如下:

[root@localhost~] sed -i '2i\con' file    #用法与a相同,\可加可不加。
13591641234 
con
13591641231
13591641232
13591641235
(3)c命令–整行替换

  c\,替换匹配的行(可以是n1,n2范围内的多行),用法和上述一致,略

(4)d命令–删除文本

  d,其后不带\符号,其他与上述类似

  sed -i '/vendor/d' file # 删除包含 “vendor” 的行
  sed -i '/IRTCROOM/!d' file # 删除不包含 “IRTCROOM” 的行,即仅保留包含”IRTCROOM"的行,即反向删除

(5)s命令–替换文本(最常用)

  s/.../.../g会将匹配到的文本,用新文本进行替换。注意,这里是 文本替换,不是 行替换。

  sed -i 's/C:\\Users\\go/D:\\gopath/g' file #将“C:\Users\go”替换为“D:\gopath”

  • g,表示替换所有,不带g时只替换行中的第一处匹配。另外此位置还可以是p2wpg2p

  • p,它与之前的介绍一致,表示输出行,最好与-n同时使用

  • 2,可以是任意数字n,表示替换第 n 个匹配

  • w,表示输出到文件,如sed -n 's/seu/nyue/w output' file #表示在file中将seu替换为nyue,并将替换后的所在行写入output文件

  • pg2p 即两个命令参数的组合

(6)w命令–写入新文件

  w file,将指定内容写入文件
  sed -n '1,5w output' file #将file中的1至5行写入output文件
  sed -n '/globss/w output' file #将file中globss所在行写入output文件

(7)r命令–从文件中读入文本

  r,如sed '/Centi/r otherfile' file #在file中匹配Centi的行后追加 otherfile 的内容(与前面的一个例子一致)

(8)q命令–退出命令

  q,在不完全扫描整个文本文件就可以退出

  如sed '5 q' file,即表示扫描前 5 行即退出

(9)y命令–字符映射替换

  y,与s一样的用法,如sed 'y/inchars/outchars/' file

  • 上述命令会对 inchars 和 outchars 值进行一对一的映射,即 inchars 中的第一个字符会被转换为 outchars 中的第一个字符,第二个字符会被转换成 outchars 中的第二个字符…这个映射过程会一直持续到处理完指定字符。
  • 如果 inchars 和 outchars 的长度不同,则 sed 会产生一条错误消息。
  • 转换命令是一个全局命令,也就是说,它会文本行中找到的所有指定字符自动进行转换,而不会考虑它们出现的位置
(10){} – 命令组

  {}命令组括起来的成为一组,其内多个命令用分号分隔。

  例如:

sed -n -e '/Certification/p' -e '/Certification/=' file可写成sed -n '/Certification/{p;=}' file

sed -n '/Certification/{s/i/I/g;s/le/LE/;}' file #表示在匹配到 Certification 的行中,将 i 全部替换成 I,然后将第一个 le 替换成 LE

(11)n命令–处理匹配行的下一行

  编辑命令n的意义是将匹配行的下一行读取到pattern space中,即匹配当前行的下一行

  如sed '/certi/{n;s/11/99/;}' file即在匹配到certi的行到下一行,使用s/11/99/命令进行编辑

2.4.2.2. 编辑命令的特殊表示

  • &,表示被替换的字符串,相当于一个变量用,在模式匹配时可以复用被匹配值

如,sed -n 's/seu/(&)/gp' file等同于sed -n 's/seu/(seu)/gp' file

  • ;可分隔多个编辑命令

  • 行末少打一个引号'会进入多行编辑模式

三、高级用法

3.1. 段落操作

3.1.1. :a;N;$!ba --全文预读

要求:使用seq 12 生成一个序列,最终输出如下结果:

1,2,3,4,5,6,7,8,9,10,11,12

该怎么做呢?首先seq 12的结果是一列数列

1
2
3
4
5
6
7
8
9
10
11
12

          那么我就知道我们要做什么了:我们要在每一个数字后面加个然后把他们输出到一行上。
当然你完全可以使用xargs把数列输出到一行上,然后使用sed把空格替换为,就解决了,就像这样seq 12 | xargs | sed -n 's/ /,/gp'
          但有的时候我们要面对的是很复杂的数据,这个时候可能需要把整个输入都预读到pattern space中进行替换处理。那么:a;N;$!ba这个固定用法正是用来解决这个问题,它可以把整个输入或者文件的内容全部(包括换行符\n)预读到pattern space中进行统一处理。用法如下:

sed -n ':a;N;$!ba;s/\n/,/gp'

  • :a是一个标签,它通常和ba是一起使用的,表示一个循环的开始和结束,前面说到,当b命令遇到一个标签后,会使sed跳转到这个标签的起始位置继续执行。这里a就是这个标签,:表示标签的开始,但a不是固定的,它可以是任意字母或字母组合,只要与b后面的标签一致即可。

  • N命令表示把当前输入的内容追加到pattern space中。由于sed的动作是从标签a开始的,当处理到命令b的时候,获取到b后面的标签a,然后就跳转到a的开始位置继续读取新行并执行命令N

  • $ 表示最后一段

  • ! 表示否定

          $!ba就表示最后一行不跳转到标签 a ,也就是只要不是最后一行,每读取完一行都要跳转到 :a 的位置重新开始,只有读取到了最后一行,才继续进行后面的替换命令。所以,整条命令解释过来,就是sed按行进行读取,并且把读取到的每一行都执行N命令添加到pattern space,直到添加完最后一行,才继续执行后面的替换动作。

[root@localhost]# seq 12 | sed -n ':a;N;$!ba;s/\n/,/gp'
1,2,3,4,5,6,7,8,9,10,11,12

3.1.2. :a;N;/\n$/!{$!ba} – 以空行分割按段预读

          与上一个命令类似,不同的是,这个命令适合处理多段文字以空格间隔的场景,实现的效果是以空格为分割,对每段文字进行处理,而不是同时处理全部文字。如下面这个例子是参考某大神提出的:

文本:
Handle 0x0058, DMI type 20, 19 bytes
Memory Device Mapped Address
        Starting Address: 0x0001FFFFC00
        Ending Address: 0x0001FFFFFFF
        Range Size: 1 kB
        Physical Device Handle: 0x0047
        Memory Array Mapped Address Handle: 0x004B
        Partition Row Position: Unknown
        Interleave Position: Unknown
        Interleaved Data Depth: Unknown


sample 0x0058, DMI type 20, 19 bytes
Memory Device Mapped Address
        Starting Address: 0x0001FFFFC00
        Ending Address: 0x0001FFFFFFF
        Range Size: 2 kB
        Physical Device Handle: 0x0047
        Memory Array Mapped Address Handle: 0x004B
        Partition Row Position: Unknown
        Interleave Position: Unknown
        Interleaved Data Depth: Unknown


Handle 0x0058, DMI type 20, 19 bytes
Memory Device Mapped Address
        Starting Address: 0x0001FFFFC00
        Ending Address: 0x0001FFFFFFF
        Range Size: 3 kB
        Physical Device Handle: 0x0047
        Memory Array Mapped Address Handle: 0x004B
        Partition Row Position: Unknown
        Interleave Position: Unknown
        Interleaved Data Depth: Unknown
要求:每个段落是Handle开头的就取出Range Size的值:
1 kB
3 kB


sed -n '/^Handle/{:a;N;/\n$/!{$!ba};s/.*Range Size: \([^\n]*\).*/\1/p}' file

[解析]
          文本就3个段落,2个空行为分割,首先想到肯定是以空行为分割,把一整段文本读取在一起,然后统一进行匹配和替换。特别注意N读取内容匹配空行是 /\n$/ ,而不是一般的 /^$/ 。因此,我们可以使用sed的段落处理命令 :a;N;$!ba 来处理这个问题,而在这个场景下,我们使用的是 :a;N;/\n$/!{$!ba} ,以空行分割按段预读处理。

为什么要用 /\n$/!{$!ba} 而不是直接用 /\n$/!ba

          笔者曾在实验的时候曾纠结过这个问题,原因是给定的文本中,最后一行不是空行,因此当sed处理到最后一行时,由于没有 \n$ 来匹配 /\n$/!ba ,因此sed仍然会执行 ba 从而跳转到开始来执行 N,当sed发现没有下一行可以追加了,就会结束动作而不再进行后续的替换操作。因此除非最后一行是空行,否则使用 /\n$/!ba 会导致最终的处理结果不包含最后一个空行之后的内容。

          因此,我们使用 /\n$/!{$!ba} ,保证sed在处理到最后一行的时候,能够不再继续跳转到 N; 而是继续后面的替换动作。
还有另外的一个例子大家可以去这个大神的文章《sed之h;H和:a;N;ba使用精解(对段落进行操作》去看一下,不再多讲。

参考

https://www.jianshu.com/p/c45788346b26
http://blog.chinaunix.net/uid-10540984-id-2983419.html

你可能感兴趣的:(Shell学习笔记,linux,运维)