sed命令基本概念
sed命令每次只能处理一行数据,数据的来源可以是:键盘输入、重定向、字符串、文件。每次从元数据读取一行放入缓冲区,依次执行sed命令,直到所有命令完成,再处理下一行。循环往复,直到所有数据行处理完成。
sed命令常见的执行方式有两种,如下:
- shell命令中直接使用
sed [option] 'command' input_file
- 把sed命令放在文件里,使用时用-f选项指定。
sed [option] -f sed_script_file input_file
sed命令选项
sed命令的选项数量不多,使用起来也不复杂,主要一下几个:
- -n:不打印所有的行到标准输出,配合p命令使用,输出实际操作的行。
- -e:用于指定后面的串也是sed命令,用于连接多条sed命令。
- -f:把所有sed命令放在一个文件里,执行时用-f选项指定文件名。
- -i:in place。在输入文件上直接进行操作,会影响到输入文件。慎重使用。
- -r:在sed的命令部分使用扩展正则语法。
sed文本定位方式
由于sed命令是基于行操作的命令,那么sed是如何定位某一行呢?主要有如下几种方式。
- 定位某一行
- 用数字定位行,这是最简单粗暴的方式。
# 打印input.txt的第4行,配合-n选项,其他的行不会被打印
sed -n '4p' input.txt
- 内置符号$,用于定位最后一行
sed -n '$p' input.txt
- 定位某些行
- 包含某个字符串的行,可以使用正则表达式,默认只支持基础正则语法,使用-r选项支持扩展正则语法。具体参见似是而非的正则语法规则。
# 包含abc的行,查找字符串的语法必须是/xxx/前后两个斜杠都需要
sed -n '/abc/p' input.txt
# hello开头的行
sed -n '/^hello/p' input.txt
# 包含至少5个连续字母a的行,下面两个命令等价,原因参见上面的链接
sed -n '/a\{5,\}/p' input.txt
sed -n -r '/a{5,}/p' input.txt
- 等差行号定位法
# 定位奇数行,从第1行开始,步长为2
sed -n '1~2p' input.txt
# 从第10行起,步长为3,即输出10 13 16...行
sed -n '10~3p' input.txt
- 定位一个区间的行:区间的两个端点可以是上面定位一行的方式的任意组合,用逗号隔开左右端点。示例如下:
# 1-10行
sed -n '1,10p' input.txt
# 5到最后一行
sed -n '5,$p' input.txt
# 1到下一个(从下一行起,没有则到最后一行)包含abc的行
sed -n '1,/abc/p' input.txt
# 第一个包含abc的行到从此行开始下一个找到def的行,
# 如果abc找不到则没有任何输出,def找不到则找到最后一行
sed -n '/abc/,/def/p' input.txt
行区间的定位还有另外一种方式,我把他叫做紧随其后行。
# 找到abc及其后3行,这里3的意思是再来3行
# 左端点可以是上面定位一行的任意方式
sed -n '/abc/,+3p' input.txt
- 反向选择上面的行
在上述所有的行定位的方式的基础上,在其后面紧随一个!,表示反向选择行,示例如下:
# 除了第1行都输出
sed -n '1!p' input.txt
# 偶数行
sed -n '1~2!p' input.txt
# 不包含abc的行
sed -n '/abc/!p' input.txt
sed行操作示例
在上面的行定位中,我们只用了行处理的p操作。还有其他很多操作,如下:
p:打印本行
=:打印行号
a\:在定位行后插入文本,可以插入多行,需要用\分隔
i\:在定位行前插入文本
d:删除定位行
c\:用新文本替换定位行
r:从另一个文本中读
w:把定位行写入到一个文件
y:把定位行的字符进行替换
{}:在定位行执行一组命令
s:使用替换模式
还有复杂的和缓冲区相关的后面单独讲
以上为常用处理操作,看示例吧
# 打印包含abc的行
sed -n '/abc/p' input.txt
# 打印最后一行
sed -n '$p' input.txt
# 打印奇数行行号
sed -n '1~2=' input.txt
# 包含abc的行号
sed -n '/abc/=' input.txt
# 在20行后插入hello
sed '20a\hello' input.txt
# 1 4 7..行后插入what the fuck
sed '1~3a\what the fuck' input.txt
# 删除带abc的行
sed -n '/abc/d' input.txt
# 删除第一处包含abc的行及其后2两行
sed -n '/abc/,+2d' input.txt
# 把包含error的行,替换为what
sed '/error/\cwhat' input.txt
# 在包含John的行后面,插入文件score.txt的内容,和\a很像
sed '/John/r score.txt' input.txt
# 把定位的行输出到指定的文件中
sed '/some lines/w out.txt' input.txt
# 在定位行执行字符替换操作:把abc->ABC
sed '1~2y/abc/ABC/' input.txt
# 使用{}包括一组命令,按顺序执行,相当于用-e连接,下面命令等价,注意分号
sed '/1~2{y/abc/ABC/;y/ABC/WTF/;}' input.txt
sed -e '1~2y/abc/ABC/' -e '1~2y/ABC/WTF' input.txt
# s替换字符串
# abc->she
sed 's/abc/she/' input.txt
# 用()包围的内容,改为用{}包围,这里是贪心匹配,sed不支持非贪心模式
sed 's/(\(.*\))/{\1}/g' input.txt
# 替换默认只替换本行的第一个匹配,要替换所有请加g选项
sed 's/abc/DEF/g' input.txt
# 利用{}配合n选项进行操作,名字后面一行是成绩,用于修改成绩
sed '/john/{n;s/score=59/score=100/;}' input.txt
若sed命令放在shell脚本里,并且要使用shell中的变量时,请用双引号代替单引号包裹命令。
高级用法,不常用
两种缓冲区:模式缓冲区(pattern buffer)、保持缓冲区(hold buffer)
五个缓冲区操作命令:
- g: 将hold space中的内容拷贝到pattern buffer中,原来pattern buffer里的内容清除
- G: 将hold buffer中的内容append到pattern buffer\n后
- h: 将pattern buffer中的内容拷贝到hold buffer中,原来的hold space里的内容被清除
- H: 将pattern buffer中的内容append到hold buffer\n后
- x: 交换pattern buffer和hold buffer的内容
初始情况下模式缓冲区和保持缓冲区内容为空,然后逐行读取内容到模式缓冲区,一般情况下就在模式缓冲区上操作,不会用到保持缓冲区,也不会影响到源文件,毕竟是拷贝过来的。上面五个命令就是在倒腾模式缓冲区和保持缓冲区的内容。需要注意的两点是:
- 模式缓冲区的内容会被每次读取的行替代
- 保持缓冲区的内容不会主动变化,除非你用上面的h H x命令。
# input.txt内容如下3行
# one
# two
# three
sed -n 'H;g;p;' input.txt
# output:
# 空行
# one
# 空行
# one
# two
# 空行
# one
# two
# three
执行H命令时,模式缓冲区已经读入了第一行内容,所以执行H命令后,把第一行内容附加到保持缓冲区后,并且自动换行,再执行命令g把保持缓冲区的内容(一个空行 one)赋值回模式空间,再执行命令p把模式缓冲区的内容打印出来(打印的总是模式缓冲区的内容)。当读取下一行内容时,模式缓冲区又被替换为读取内容(two),保持缓冲区内容不变(一个空行 one),如此往复构成了这个执行结果。
翻来覆去,一顿操作,暂时看不到使用场景,可以先放着吧。
网友评论