<!--title:Linux Sed命令详解-->
<!--category:技术学习-->
<!--tags:sed, linux, 正则表达式-->
<!--author:Neal-->
<!--date:2016-03-18-->

### 概述
`sed`是`stream editor`的简称，也就是流编辑器。它一次处理一行内容，处理时，把当前处理的行存储在临时缓冲区中，称为`"pattern space"`，接着用`sed`命令处理缓冲区中的内容，处理完成后，把缓冲区的内容送往屏幕。接着处理下一行，这样不断重复，直到文件末尾。文件内容并没有 改变，除非你使用重定向存储输出。

### 语法
#### 命令格式
`sed [option] 'command' input_file`

#### 常用选项
* `-n` 使用安静`silent`模式。在一般`sed`的用法中，所有来自`stdin`的内容一般都会被列出到屏幕上。但如果加上`-n`参数后，则只有经过`sed`特殊处理的那一行(或者动作)才会被列出来

* `-e` 直接在指令列模式上进行 `sed` 的动作编辑

* `-f` 直接将 `sed` 的动作写在一个文件内，`-f filename`则可以执行`filename`内的`sed`命令

* `-r` 让`sed`命令支持扩展的正则表达式(默认是基础正则表达式)

* `-i` 直接修改读取的文件内容，而不是由屏幕输出

#### 常用命令
* `a\`：追加行，`a\`的后面跟上字符串`s`(多行字符串可以用`\n`分隔)，则会在当前选择的行的后面都加上字符串`s`

* `c\`：替换行，`c\`后面跟上字符串`s`(多行字符串可以用`\n`分隔)，则会将当前选中的行替换成字符串`s`

* `i\`：插入行，`i\`后面跟上字符串`s`(多行字符串可以用`\n`分隔)，则会在当前选中的行的前面都插入字符串`s`

* `d`：删除行`delete`，该命令会将当前选中的行删除

* `p`：打印`print`，该命令会打印当前选择的行到屏幕上

* `y`：替换字符，通常`y`命令的用法是这样的：`y/Source-chars/Dest-chars/`，分割字符`/`可以用任意单字符代替，用`Dest-chars`中对应位置的字符替换掉`Soutce-chars`中对应位置的字符

* `s`：替换字符串，通常`s`命令的用法是这样的：`1,$s/Regexp/Replacement/Flags`，分隔字符`/`可以用其他任意单字符代替，用`Replacement`替换掉匹配字符串

#### 替换选项
* `\digit`：`Replacement`中可含有后向引用中的`\digit`(`digit`是`1`至`9`)，引用前面定义的子表达

* `&`：代表模版空间中的整个匹配部分

* `\L`：将在其后的替换部分转换成小写字母，直到发现一个`\U`或`\E`，`GNU`扩展功能

* `\l`：将下一个字符转换成小写字母，`GNU`扩展功能

* `\U`：将在其后的替换部分转换成大写字母，直到发现一个`\L`或`\E`，`GNU`扩展功能

* `\u`：将下一个字符转换成大写字母，`GNU`扩展功能

* `\E`：停止由`\L`或`\U`指示开始的大小写转换，`GNU`扩展功能

#### 标志选项
* `g`：将用`Replacement`替换模版空间中所有匹配`Regexp`的部分，则不仅仅是第一个匹配部分

* `digit`：只用`Replacement`替换模版空间中第`digit`(`digit`是`1`至`9`)个匹配`Regexp`的部分

* `p`：若发生了替换操作，指示显示模版空间中新的数据

* `w file-name`：若发生了替换操作，指示将模版空间中新的数据写入指定的文件`file-name`中

* `i`：表示进行`Regexp`匹配时，是不区分大小写字母的

### 示例
#### `a`命令
* `sed '1,$a\add one' test.txt` 从第一行到最后一行所有行后追加`"add one"`字符串行

* `sed '/first/a\add one' test.txt` 在匹配到`first`行追加`"add one"`字符串行

#### `i`命令
与`a`命令类似，只不过在匹配的行前面插入字符串行，不举例了。

#### `c`命令
* `sed '1,$c\add one' test.txt` 从第一行到最后一行所有行替换为`"add one"`字符串行

* `sed '/first/c\add one' test.txt` 将匹配到`first`行替换为`"add one"`字符串行

#### `d`命令
* `sed '4,$d' test.txt` 从第四行到最后一行全部删除

#### `p`命令
* `sed -n '/^first.*end$/p' test.txt` 以`first`开头`end`结尾的所有行全部打印

#### `s`命令
* `sed 's/line/text/g' test.txt` 将所有行的`line`替换为`text`，`g`代表全局选项，没有`g`只替换所有行的第一个匹配项

* `sed '/^first.*end$/s/line/text/g' test.txt` 匹配以`first`开头`end`结尾的所有行，然后将`line`全部替换为`text`

* `sed 's/\(.*\)line$/\1/g' test.txt` 本例中的`\(\)`中包裹的内容表示正则表达式的第`n`部分，`.*`表示任意字符串，所以此例相当于删除所有行末的`line`

### 基本正则表达式
| 元字符              | 说明                                                                                                                |
|:-------------------:|:--------------------------------------------------------------------------------------------------------------------|
| `*`                 | 将`*`前面的正则表达式匹配的结果重复任意次(含`0`次)。                                                                |
| `\+`                | 与星号(`*`)相同，只是至少重复`1`次，`GNU`的扩展功能。                                                               |
| `\?`                | 与星号(`*`)相同，只是最多重复`1`次，`GNU`的扩展功能。                                                               |
| `\{i\}`             | 与星号(`*`)相同，只是重复指定的`i`次。                                                                              |
| `\{i,j\}`           | 与星号(`*`)相同，只是重复`i`至`j`次。                                                                               |
| `\{i, \}`           | 与星号(`*`)相同，只是至少重复`i`次。                                                                                |
| `\(regexp\)`        | 将`regexp`看作一个整体，用于后向引用，与`\digit`配合使用。                                                          |
| `.`                 | 匹配任意单个字符。                                                                                                  |
| `^`                 | 匹配模版空间开始处的`NULL`字符串。                                                                                  |
| `$`                 | 匹配的是模版空间结束处的`NULL`字符串。                                                                              |
| `[list]`            | 匹配方括号中的字符列表中的任意一个。                                                                                |
| `[^list]`           | 否定匹配方括号中的字符列表中的任意一个。                                                                            |
| `regexp1\|regexp2`  | 用在相邻的正则表达式之间，表示匹配这些正则表达式中任一个都可以。匹配是从左向右开始的，一旦匹配成功就停止匹配。      |
| `regexp1regexp2`    | 匹配`regexp1`和`regexp2`的连接结果。                                                                                |
| `\digit`            | 匹配正则表达式前半部分定义的后向引用的第`digit`个子表达式。`digit`为`1`至`9`的数字, `1`为从左开始。                 |
| `\n`                | 匹配换行符。                                                                                                        |
| `\meta`             | 将元字符`meta`转换成普通字符，以便匹配该字符本身，有`$`、 `*`、 `.`、 `[`、 `\` 和 `^`。                            |

Table: `BRE`元字符表

### 扩展正则表达式
扩展正则表达式除了以下元字符与基本正则表达式不同外，其余相似。

| 基本正则表达式 | 扩展正则表达式 |
|:--------------:|:--------------:|
| `\?`           | `?`            |
| `\+`           | `+`            |
| `\|`           | `|`            |
| `\{ \}`        | `{ }`          |
| `\( \)`        | `( )`          |

Table: `BRE`与`ERE`元字符对应表

### 常用转义字符
| 转义字符    | 说明                                                                                 |
|:-----------:|:-------------------------------------------------------------------------------------|
| `\a`        | 匹配一个`BEL`字符。                                                                  |
| `\f`        | 匹配一个换页字符。                                                                   |
| `\n`        | 匹配一个换行字符。                                                                   |
| `\r`        | 匹配一个回车字符。                                                                   |
| `\t`        | 匹配一个水平`Tab`字符。                                                              |
| `\v`        | 匹配一个垂直`Tab`字符。                                                              |
| `\cX`       | 匹配`Control+X`，`X`是任意字符。                                                     |
| `\dXXX`     | 匹配一个`ASCII`码是十进制`XXX`的字符。                                               |
| `\oXXX`     | 匹配一个`ASCII`码是八进制`XXX`的字符。                                               |
| `\xXX`      | 匹配一个`ASCII`码是十六进制`XX`的字符。                                              |
| `\w`        | 匹配任意一个单词字符(字母、数字和下划线)。                                           |
| `\W`        | 匹配任意一个非单词字符。                                                             |
| `\b`        | 匹配一个单词的边界符：字符的左边是一个单词字符，并且右边是一个非单词字符，反之亦然。 |
| `\B`        | 匹配除单词边界符外所有字符：字符的左边和右边同时是单词字符或非单词字符。             |

Table: 转义字符表
