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,输出到屏幕。
$ sed -e '/sunny/ p' -e 's/sunny/rainy/g' << EOF
sunny
EOF上例的输出为:
sunny
rainy
之所以不是两个rainy的原因是,command1仅仅是将包含sunny的行输出到屏幕,传给command2的依然只是当前处理的这行,而不会把输出到屏幕的那行也传给command2
$ sed -e '/sunny/ p' -e '/sunny/ d' -e 's/sunny/rainy/g' << EOF
sunny
EOF上例的输出为:
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