sed 是一个精简的、非交互式的编辑器,可以提供与编辑器 VIM 或者 EMACS 相同的编辑任务,但 sed 不提供交互使用方式,只能在命令行下输入编辑命令。
这里简单介绍其使用方法。
简介
常用操作如下。
sed 默认会打印所有的处理行,可以通过 -n
参数取消默认的打印,例如,可以通过 /Pattern/p
参数,那么此时只会打印匹配的行。
----- 全局替换匹配行,s 替换,g 全局
$ sed -i 's/^a.*/haha/g' filename
----- 文件头部添加一行,命令1表示第一行,i表示插入,之后是内容
$ sed -i "1ifoobar" filename
i 行前插入 insert
a 行后插入 append
c 行替换 change
----- 规则匹配行前插入
$ sed -i "/foobar/ifoo" filename
----- 删除指定行,$表示最后一行
$ sed -i '1d' filename
$ sed -i '$d' filename
$ sed -i '/foobar/d' filename
注意,通过 -i
参数会直接替换原文件的内容,否则只会在打印的信息中进行相关处理,而非修改原文件。
可以通过如下命令删除两个标记行之间的内容,相关帮助可以通过 info sed
查看。
----- 查看输出,没有问题直接替换
$ sed '0,/^#YOUR-MARK-BEGIN$/{//d;b};0,/^#YOUR-MARK-END$/d' # 只删除第一个匹配
$ sed '/^#YOUR-MARK-BEGIN$/, /^#YOUR-MARK-END$/d' # 删除所有匹配
$ sed -i -e '0,/^#YOUR-MARK-BEGIN$/{//d;b};0,/^#YOUR-MARK-END$/d'
示例
crontab 替换
因为会涉及到文件路径,而其中的匹配字符 /
会与其冲突,可以使用 %
,示例如下。
----- 只替换文件的路径
sed -i -n 's%/Your/File/Path%/Your/New/File/Path%g' /etc/crontab
----- 替换整行
sed -i -n 's%^.* /Your/File/Path .*$%* */5 * * * root /Your/New/File/Path >/dev/null 2>\&1%g' /etc/crontab
当然,也可以先删除,然后再在最后一行添加。
sed -i '/\/Your\/File\/Path/d' /etc/crontab
sed -i '$a * */10 * * * root /Your/New/File/Path >/dev/null 2>&1' /etc/crontab
注意,如果是只打印,没有找到太好的方法。
sed -n '/\/Your\/File\/Path/g' /etc/crontab
多行替换
sed 经常用来替换文件的内容,通常是处理单行的,但通过它的一些内建功能,也能实现多行替换。假设有如下的文本:
hello <<<comment part 1
comment part 2>>>
foobar
现在需要把 <<< ... >>>
这一段替换为 “COMMENT”,那么 sed 语法应当是:
:begin
/<<</,/>>>/ {
/>>>/! {
$! {
N;
b begin
}
}
s/<<<.*>>>/COMMENT/;
}
上述语句存储在 test.sed 中,那么执行的方式和结果就是:
$ sed -f foobar.sed foobar
hello COMMENT
foobar
把正则直接写到命令里面也可以,用 ";"
来分隔命令即可,注意右花括号之后也要加上分号 ";"
,如果再加上 -i 参数就可以直接把改动写到原文件中去了:
$ sed -e ":begin; /<<</,/>>>/ { />>>/! { $! { N; b begin }; }; s/<<<.*>>>/COMMENT/; };" test
hello COMMENT
foobar
各个步骤介绍如下:
- 花括号
{}
代表命令块的开始,类似 C 语法; :begin
是一个标号 (label),用于跳转,供 b、t、T 等命令使用,这里使用了 b 命令;/<<</,/>>>/
通过逗号分隔 (开始+结束位置) 用于标示地址范围,后面 {} 中的命令只对地址范围之间的内容使用。/>>>/!
$!
其中叹号表示取反,而 $ 在 sed 中表示为最后一行,也就意味着 “如果在本行没有发现结束标记,而且本行不是文件的最后一行” 那么执行下面的操作;N;
用于把下一行的内容追加到缓冲区 (pattern),也就是相当于合并为一行;b begin
由于仍然没有找到结束标记跳回到 begin,重新执行追加命令;s/<<<.*>>>/COMMENT/;
匹配完成之后,可以通过该命令替换。
参考
详细内容可以查看官方手册 sed, a stream editor 中的内容。