使用的是gnu sed, mac 下默认是bsd sed, mac下可以brew install gnu-sed

Stream EDitor, 流编辑器

格式

sed options script file

* -e script 可以指定多个-e(后面举例)
* -f file 从文件读取sed规则
* -n 只输出匹配的行

替换(substitute)

s/pattern/replacement/flag

* 数字        表明新文本将替换第几处模式匹配的地方
* g         所有匹配的都替换
* p         原来的内容也打印出来
* w file    将替换的结果写到文件中

限制行数

* 数字            指定行数
* 数字1,数字2   限定范围
* $表示结尾行
*
* 其实还可以使用文本模式过滤器
* /pattern/command 
* eg. $ sed '/tankywoo/s/bash/csh/' /etc/passwd

删除行

sed 'd' mydata      #删除全部
sed '1d' mydata     #删除第一行

这个同样也可以用于上面的模式匹配

插入和附加

插入i会在指定行前插入一个新行
插入a会在指定行后插入一个新行
echo "Test Line 2" | sed 'i\Test Line 1'
echo "Test Line 2" | sed 'a\Test Line 1'

指定在某行插入字符串:

# 在第5行插入hello world
% sed -i '5ihello world' FILE

参考 Insert a line at specific line number with sed or awk

修改

字符c是修改指定行的整行内容
sed '3c\'       #修改第三行

转换

字符y是进行单个字符映射的转换,且是全局的
sed 'y/abc/123' mydata
会将所有的a转换成1b转换成2c转换成3

打印

* p 打印问本行
* # 打印行号
* l 列出行

文件操作

* w 写入文件
* r 读入文件

(以下内容参考 Software Design 03期的sed详解及用法)

源文件:

$ more input.txt
aaabbbcccddd aaabbbcccddd
AAABBBCCCDDD aaabbbcccddd
1234567890!? !"#$%&'()?/'"

简单的替换:

$ sed -e 's/bbb/eee/' input.txt
aaaeeecccddd aaabbbcccddd
AAABBBCCCDDD aaaeeecccddd
1234567890!? !"#$%&'()?/'"

第一行前半部分的bbb被替换了, 后半部分没有; 第二行替换了;

因为sed是流编辑器, 以行为处理单元, 默认一行处理一次;

这里的-e没什么用, 可以不写.

可以加上g标志, 表示全局作用:

$ sed -e 's/bbb/eee/g' input.txt
aaaeeecccddd aaaeeecccddd
AAABBBCCCDDD aaaeeecccddd
1234567890!? !"#$%&'()?/

也可以在指定行上操作, 如只在第一行:

$ sed -e '1s/bbb/eee/g' input.txt
aaaeeecccddd aaaeeecccddd
AAABBBCCCDDD aaabbbcccddd
1234567890!? !"#$%&'()?/

sed的基本格式:

sed [选项, -e] '[开始行,结束行]命令/查找字符串/替换字符串/[标志, g]' 输出文本 [> 输出文本]

关于命令, 除了s(替换), 还有:

标志除了g(global全局), 还有:

可以同时指定多个标志

sed的默认分隔符是`/', 可以替换为其它字符. 比如替换路径时, 因为用反斜杠转义比较麻烦, 可以改分隔符:

$ sed 's!/bin/bash!/bin/zsh!' /etc/passwd

替换字符串中, &表示匹配的字符串:

$ sed -e 's/bbb/+&+/g' input.txt
aaa+bbb+cccddd aaa+bbb+cccddd
AAABBBCCCDDD aaa+bbb+cccddd
1234567890!? !"#$%&'()?/

$ sed -e 's/.*/output: &/g' input.txt
output: aaabbbcccddd aaabbbcccddd
output: AAABBBCCCDDD aaabbbcccddd
output: 1234567890!? !"#$%&'()?/

p标志会打印替换的行(替换后的内容), 可以配合-n只输出替换的行:

$ sed -e 's/aaa/EEE/' input.txt
EEEbbbcccddd aaabbbcccddd
AAABBBCCCDDD EEEbbbcccddd
1234567890!? !"#$%&'()?/

$ sed -e 's/aaa/EEE/p' input.txt
EEEbbbcccddd aaabbbcccddd
EEEbbbcccddd aaabbbcccddd
AAABBBCCCDDD EEEbbbcccddd
AAABBBCCCDDD EEEbbbcccddd
1234567890!? !"#$%&'()?/

$ sed -n -e 's/aaa/EEE/p' input.txt
EEEbbbcccddd aaabbbcccddd
AAABBBCCCDDD EEEbbbcccddd

w标志后接输出文件, 只写入替换的行; w命令输出包括不匹配的行:

$ sed -e 's/aaa/EEE/w output.txt' input.txt
EEEbbbcccddd aaabbbcccddd
AAABBBCCCDDD EEEbbbcccddd
1234567890!? !"#$%&'()?/

$ more output.txt
EEEbbbcccddd aaabbbcccddd
AAABBBCCCDDD EEEbbbcccddd

$ sed -e 's/aaa/EEE/' -e 'w output.txt' input.txt
EEEbbbcccddd aaabbbcccddd
AAABBBCCCDDD EEEbbbcccddd
1234567890!? !"#$%&'()?/

$ more output.txt
EEEbbbcccddd aaabbbcccddd
AAABBBCCCDDD EEEbbbcccddd
1234567890!? !"#$%&'()?/

y 命令替换1个字符, 可以同时替换多个字符(和s命令不一样, y会替换一行中所有匹配的, 不需要g标志):

# a -> E
$ sed -e 'y/a/E/' input.txt
EEEbbbcccddd EEEbbbcccddd
AAABBBCCCDDD EEEbbbcccddd
1234567890!? !"#$%&'()?/

# a -> E; b -> F
$ sed -e 'y/ab/EF/' input.txt
EEEFFFcccddd EEEFFFcccddd
AAABBBCCCDDD EEEFFFcccddd
1234567890!? !"#$%&'()?/

d 命令删除, 可以指定行或全部:

$ sed -e '2d' input.txt
aaabbbcccddd aaabbbcccddd
1234567890!? !"#$%&'()?/

$ sed -e '1,2d' input.txt
1234567890!? !"#$%&'()?/

# 输出空
$ sed -e 'd' input.txt

地址(限制行数):

例子:

$ more input.txt
abcd
1234
1aff
cd23

$ sed '/^[0-9]/s/.*/output: &/' input.txt
abcd
output: 1234
output: 1aff
cd23

执行多个命令. 这里就是-e的用处了; 还可以用;分割:

$ sed -e '2d' -e 's/bbb/EEE/' input.txt
aaaEEEcccddd aaabbbcccddd
1234567890!? !"#$%&'()?/

$ sed '2d;s/bbb/EEE/' input.txt
aaaEEEcccddd aaabbbcccddd
1234567890!? !"#$%&'()?/

关于写文件, 除了之前用到的重定向标准输出, w命令/标志, 还可以用-i直接写源文件本身.

在-i可接一个后缀表示先备份替换前的源文件, 再直接写入源文件:

$ sed -i.bak '2d;s/bbb/EEE/' input.txt

$ more input.txt
aaaEEEcccddd aaabbbcccddd
1234567890!? !"#$%&'()?/

$ more input.txt.bak
aaabbbcccddd aaabbbcccddd
AAABBBCCCDDD aaabbbcccddd
1234567890!? !"#$%&'()?/

注意, 一般情况下, sed的替换规则用单引号, 除非想使用一些自定义或环境变量.

可以把sed的替换命令写入文件, 使用-f选项读取.

$ more sample.sed
2d
s/bbb/EEE/

$ sed -f sample.sed input.txt
aaaEEEcccddd aaabbbcccddd
1234567890!? !"#$%&'()?/

可以用花括号{}对命令进行组合:

$ more sample.sed
1,3{
        s/aaa/EEE/g
        y/abc/XYZ/
}

$ sed -f sample.sed input.txt
EEEYYYZZZddd EEEYYYZZZddd
AAABBBCCCDDD EEEYYYZZZddd
1234567890!? !"#$%&'()?/

资料