个人觉得 sed 的主要优势就是可以实现文本处理自动化。流编辑器会在编辑器处理数据之
前提供一组规则,这点与交互式编辑器不同。
命令格式
1  | sed [OPTION]... {script-only-if-no-other-script} [input-file]...  | 
script参数指定了应用于数据流上的单个命令,可以使用-e参数来指定多个命令,或者
使用-f参数指定 sed 脚本文件。
替换命令 s
1  | [range]s/regexp/replacement/flags  | 
示例如下:
1  | echo "I do not like qt" | sed 's/do not/do/'  | 
第四和第五个命令是一样的,只是写法不同。注意多个命令时,最后的单引号要和文件在同
一行上,shell 在接收到最后的单引号时就会开始执行命令,这时会从标准输入读取,而不
会读取文件。这里替换命令跟 vim 中的几乎一样(我不清楚他们的正则表达式语法是否相
同),如果你经常使用 vim 下的这个命令,会感到非常亲切。
也可以将命令写到文件里,如下所示:
1  | sed cat script.sed  | 
这种情况下分号不是必须的。
替换命令的 flag 包括:
| cmd | description | 
|---|---|
| n | 替换第 n 个出现的匹配 | 
| g | 替换所有的匹配 | 
| p | 输出修改过的行 | 
| w file | 将结果写到 file 中 | 
示例如下:
1  | cat data1  | 
可以看到 flag 也是可以组合的。一般标志p与-n一起使用,-n使得 sed 默认不输出。
最后一个例子比较有意思,可以看到 sed 从第 3 个匹配开始替换了其后所有匹配到的文本。
sed 的分隔符并不一定要是/,比如:
1  | which env | sed 's+/usr/bin+/bin+'  | 
这里使用了+,可以根据需要尝试。
sed 的所有命令都可以指定作用范围,范围的表示可以有多种,比如用行号或正则表达式,
请看以下例子:
1  | cat data5  | 
范围可以指定某些行,也可以指定两行之间。详细说一下最后一个例子。
/^two/,/^four/s/text/changed/中的/^two/,/^four/表示一个范围,由两个正则表达
式来表示,正则表达式是/之间的文本,/^two/表示以 two 开头的行,/^four/表示
以 four 开头的行,后面是一个替换命令s/text/changed/将 text 替换为 changed。注
意包围正则表达式的/不能随意更换,这与替换命令中的/不同。
再看下面一个例子:
1  | cat data7  | 
命令1,2{s/text/changed/; s/left/right/}; 3,4s/up/down/的作用是,在 1~2 行和
3~4 行上分别执行不同的命令,其中 1~2 行上针对每行执行两条命令,分别是两个替换。
删除命令 d
这个命令就非常简单了,看下面这个例子:
1  | cat data  | 
最后一个命令使得被匹配到的行在删除前打印出来。
插入命令i 和 附加命令a
这两个命令分别在指定行的前或后增加新行,格式为:
1  | sed '[range]cmd\<text>'  | 
示例如下:
1  | cat data  | 
注意在i/a之后\后面的内容(除了单引号)会被认为是要插入文本的一部分,所以结尾
的花括号不能与命令写在同一行上。要插入或附加多行文本的话,需要在除最后一行之外每
行的末尾加上\。
行修改命令 c
格式与插入附加命令一样,只是c会将原本的内容删除,替换为新的文本。如下:
1  | sed '2c\------\  | 
字符转换命令 y
格式为:
1  | [range]y/oldchars/newchars/  | 
oldchars和newchars的长度必须相同,命令会把指定行中的oldchars对应地转换为newchars中的字符,无法限定转换特定位置的字符。如:
1  | sed 'y/to/-=/' data  | 
其他打印命令 p = l
他们的意义分别为:
| cmd | description | 
|---|---|
| p | 打印文本行 | 
| = | 打印行号 | 
| l | 打印不可见字符 | 
p命令与替换命令中的标识 p 相似,表示输出该行,如:
1  | sed -n '2p' data  | 
读取命令 r 和 写入命令 w
直接看例子:
1  | cat data  | 
其中,2,$w output表示将从第 2 行开始到文件末尾输出到文件output。