sed tips
1. sed 的调用格式
sed
的调用格式在大多数场合下如下:
$ sed 'address command' < input_file > output_file
单引号里面的部分大致分为两部分:
-
地址范围部分:
如果没有指出地址范围,则后面的
command
会作用到输入文件的每一行;如果指定了地址范围,则可能有几种情况:
- 只有一个数字(例如:
10
),则command
只会作用该行 - 只有一个pattern(例如:
/^#/
),则command
只会作用在满足pattern的那行。这里的pattern的分割符默认是/
,但是可以通过加反斜杠的方式换用别的分割符,例如:/pattern/ <-> \:pattern: <-> \_pattern_
- 有一对数字(例如:
10,20
),则command
只会作用在第10
到20
行(闭区间); - 有一对pattern(例如:
/start/,/end/
),则command
只会作用在包含start
的行至包含end
的行(闭区间)。注意,逗号前的pattern令sed的flag打开,表示从这行开始要处理command
,而逗号后面的pattern令sed的flag关闭,表示comamnd
只作用到这行为止; - 如果
command
前加上!
则表示command
作用在除了前面的地址所表示的闭区间地址范围以外的行
- 只有一个数字(例如:
-
命令部分:
命令部分有很多,不过最广为人知的就是
s/pattern/replace/[flag][command]
了。这个命令是search and replace,可以在最后一个分割符后面加上flag或command:/g
(flag): 替换该行上的全部匹配项/I
(flag): 不区分大小写(这个也可以用于确定地址范围的pattern后面)/w file
(command): 将匹配的行写到文件file中去/p
(command): 将匹配的行输出
2. sed 中有多个”address command”
首先需要明确的是,由于sed是基于行进行处理的。即,sed
会对输入文件的每一行进行操作,先根据地址范围来判断是否对该行执行command
。如果执行,则按照commnad
在命令行上的先后顺序对其进行操作(例如:print, delete, insert等等),并且前一个command
将处理后的这一行内容作为输入给下一个command
。
例如:
1
$ sed -e 's/sunny/rainy/g' -e 's/good/bad/g' < in
上例会把in
中的每一行中包括sunny
的字段改成rainy
,再将good
的字段改成bad
,输出到屏幕。
上例的输出为:
sunny
rainy
之所以不是两个rainy
的原因是,command1
仅仅是将包含sunny
的行输出到屏幕,传给command2
的依然只是当前处理的这行,而不会把输出到屏幕的那行也传给command2
上例的输出为:
sunny
之所以没有输出command3
中的rainy
,是因为在command2
中,该行已经被删掉了,因此传给command3
的是空行,因此是不会有替换和输出的。事实上,d
将所谓的__pattern space__(一个保存当前行当前内容的空间,不过这不会保存r
, i
, a
, c
所加入的内容)清空,一旦__pattern space__被清空,则后续的所有command
都不会被执行。
sed 中有多个command的语法一般有几种写法:
-
使用
-e
来区分多个address command
$ sed -e 'address1 command1' -e 'address2 command2' ... < input_file
或者
$ sed -e 'address1 command1' \ 'address2 command2' \ ... 'addressN commandN' < input_file
-
使用一对
'
符号将多对address command
括起来, 但是要保证每行上只有一个address command
$ sed 'address1 command1 address2 command2 ... addressN commandN' < input_file
-
使用
{}
将多个address command
括起来:$ read header $ sed -e '\:#include <'"$header"'>: { r '"$header"' d }
这种方式的好处在于,如果把它们写在脚本里面,可以方便地添加注释。例如:
$ read header $ sed -e '\:#include <'"$header"'>: { # read the file r '"$header"' # delete everything in pattern space # and read next line in d }
Comments