sed基础用法

post thumb
Tools
作者 Louis 发表于 2019年6月8日

[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/^/#&/,^字符匹配行首,#字符是一般字符表示添加该字符,&即表示前面的正则表达式匹配出来的部分

资料

上一篇
运维发布应考虑什么