使用的是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!? !"#$%&'()?/

在匹配行末尾加入某些字符

    [root@aliyun_file ~]# cat a.txt 
    tset
    test
    123
    [root@aliyun_file ~]# sed  '/test/s/$/000/' a.txt 
    tset
    test000
    123

在匹配行行首加入某些字符

]# cat test 
test
1234
home
sed
gerp
grep

# sed '/grep/s/^/#&/' test 
test
1234
home
sed
gerp
#grep

说明下:
s/^/#&/,^字符匹配行首,#字符是一般字符表示添加该字符,&即表示前面的正则表达式匹配出来的部分

资料