[TOC]
使用的是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 '/louis/s/bash/csh/' /etc/passwd
删除行
sed 'd' mydata #删除全部
sed '1d' mydata #删除第一行
这个同样也可以用于上面的模式匹配
插入和附加
插入i会在指定行前插入一个新行
插入a会在指定行后插入一个新行
$ echo "Test Line 2" | sed 'i\Test Line 1'
Test Line 1
Test Line 2
$ echo "Test Line 2" | sed 'a\Test Line 1'
Test Line 2
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转换成1,b转换成2,c转换成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(替换), 还有:
- d (删除)
- p (打印)
- y (替换一个字符)
- w (写文件)
- n TODO
标志除了g(global全局), 还有:
- p (print 打印)
- w (write 输出文件)
可以同时指定多个标志
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
地址(限制行数):
- 默认未指定则是所有数据
3
: 第3行20,$
: 从第20行到最后一行10,5
: 第10行; 如果结束行比开始行小, 则只有开始行/^[0-9]/
: 所有以数字开头的行15,/Z$/
: 从第15行到以Z结束的行为止5,10!
: 第5行到除第10行以外的行(5-9, 11-最后一行)
例子:
$ 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!? !"#$%&'()?/
在匹配行末尾加入某些字符
$ cat a.txt
tset
test
123
$ 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/^/#&/,^字符匹配行首,#字符是一般字符表示添加该字符,&即表示前面的正则表达式匹配出来的部分