个人觉得 sed 的主要优势就是可以实现文本处理自动化。流编辑器会在编辑器处理数据之
前提供一组规则,这点与交互式编辑器不同。
命令格式
1 | sed [OPTION]... {script-only-if-no-other-script} [input-file]... |
script
参数指定了应用于数据流上的单个命令,可以使用-e
参数来指定多个命令,或者
使用-f
参数指定 sed 脚本文件。
替换命令 s
1 | [range]s/regexp/replacement/flags |
示例如下:
1 | echo "I do not like qt" | sed 's/do not/do/' |
第四和第五个命令是一样的,只是写法不同。注意多个命令时,最后的单引号要和文件在同
一行上,shell 在接收到最后的单引号时就会开始执行命令,这时会从标准输入读取,而不
会读取文件。这里替换命令跟 vim 中的几乎一样(我不清楚他们的正则表达式语法是否相
同),如果你经常使用 vim 下的这个命令,会感到非常亲切。
也可以将命令写到文件里,如下所示:
1 | sed cat script.sed |
这种情况下分号不是必须的。
替换命令的 flag 包括:
cmd | description |
---|---|
n | 替换第 n 个出现的匹配 |
g | 替换所有的匹配 |
p | 输出修改过的行 |
w file | 将结果写到 file 中 |
示例如下:
1 | cat data1 |
可以看到 flag 也是可以组合的。一般标志p
与-n
一起使用,-n
使得 sed 默认不输出。
最后一个例子比较有意思,可以看到 sed 从第 3 个匹配开始替换了其后所有匹配到的文本。
sed 的分隔符并不一定要是/
,比如:
1 | which env | sed 's+/usr/bin+/bin+' |
这里使用了+
,可以根据需要尝试。
sed 的所有命令都可以指定作用范围,范围的表示可以有多种,比如用行号或正则表达式,
请看以下例子:
1 | cat data5 |
范围可以指定某些行,也可以指定两行之间。详细说一下最后一个例子。
/^two/,/^four/s/text/changed/
中的/^two/,/^four/
表示一个范围,由两个正则表达
式来表示,正则表达式是/
之间的文本,/^two/
表示以 two 开头的行,/^four/
表示
以 four 开头的行,后面是一个替换命令s/text/changed/
将 text 替换为 changed。注
意包围正则表达式的/
不能随意更换,这与替换命令中的/
不同。
再看下面一个例子:
1 | cat data7 |
命令1,2{s/text/changed/; s/left/right/}; 3,4s/up/down/
的作用是,在 1~2 行和
3~4 行上分别执行不同的命令,其中 1~2 行上针对每行执行两条命令,分别是两个替换。
删除命令 d
这个命令就非常简单了,看下面这个例子:
1 | cat data |
最后一个命令使得被匹配到的行在删除前打印出来。
插入命令i
和 附加命令a
这两个命令分别在指定行的前或后增加新行,格式为:
1 | sed '[range]cmd\<text>' |
示例如下:
1 | cat data |
注意在i/a
之后\
后面的内容(除了单引号)会被认为是要插入文本的一部分,所以结尾
的花括号不能与命令写在同一行上。要插入或附加多行文本的话,需要在除最后一行之外每
行的末尾加上\
。
行修改命令 c
格式与插入附加命令一样,只是c
会将原本的内容删除,替换为新的文本。如下:
1 | sed '2c\------\ |
字符转换命令 y
格式为:
1 | [range]y/oldchars/newchars/ |
oldchars
和newchars
的长度必须相同,命令会把指定行中的oldchars
对应地转换为newchars
中的字符,无法限定转换特定位置的字符。如:
1 | sed 'y/to/-=/' data |
其他打印命令 p
=
l
他们的意义分别为:
cmd | description |
---|---|
p | 打印文本行 |
= | 打印行号 |
l | 打印不可见字符 |
p
命令与替换命令中的标识 p 相似,表示输出该行,如:
1 | sed -n '2p' data |
读取命令 r
和 写入命令 w
直接看例子:
1 | cat data |
其中,2,$w output
表示将从第 2 行开始到文件末尾输出到文件output
。