sed 介绍

sed 是一个非交互式流编辑器,默认它并不修改原始文件,除非指定了 -i 或者 -i.bak 选项,前者直接修改原文件,不自动做备份,后者将原文件备份一份.bak 文件后,直接修改原文件。

sed 语法

sed [选项] '[指定要操作的行]{sed命令}' filename
命令可以用 {} 括起来

指定要操作的行

如果未指定要操作的行,则操作所有行。

可以通过行号或者正则来定位到行。

定位行的方式含义
2对第2行进行操作
2,10对第2行到第10行进行操作
2,2+3对第2行到第5(2+3)行进行操作
1~2对1,3,5,7,9....行进行操作
2,$对第2行到最后一行进行操作
/cfop/对匹配 cfop 的行进行操作
/cfop/,/cy/对匹配 cfop 的行到匹配 cy 的行进行操作
/cfop/,5对匹配到 cfop 的行到第5行进行操作
5,/cfop/对第5行到匹配到 cfop 的行进行操作
/cfop/,+2对匹配到 cfop 的行及其后的2行进行操作
2,10!不对2到10行进行操作

sed 命令之 p 打印

# sed -n '/apache/,+5{p}' /etc/passwd

sed 命令之 = 显示行号

# sed -n '/apache/=' /etc/passwd

sed 命令之 c 替换整行

# sed '/apache/c\httpd web' /etc/passwd
注意这儿是把整行替换为 httpd web,如果只想替换部分内容,使用 s 命令。

sed 命令之 d 删除行

# sed '/apache/d' /etc/passwd    删除包含关键字的行
# sed '/apache/d' /etc/passwd    删除不包含关键字的行

sed 命令之 a/i 增加行

a在指定行后面增加,i在指定行前面增加

# sed '/apache/i GOODLUCK' /etc/passwd

如果想添加多行,在行与行之间使用 n

# sed '/apache/i GOODLUCK\nMAN' /etc/passwd

sed 命令之 w 写入文件

# sed '/apache/w /tmp/sed.tmp' /etc/passwd

该命令会将包含 apache 的行写入到 /tmp/sed.tmp 文件中

sed 命令之 r 读入文件

# sed '/apache/r /tmp/sed.tmp' /etc/passwd

将 /tmp/sed.tmp 文件中的内容读入到包含 apache 的行的后面,结合上一个示例,将出现两个包含 apache 的行

sed 命令之 s 替换

s/替换谁/用什么替换/[gpw]

第一个部分的模式支持正则表达式,后面的模式不支持。这儿的 / 也可以替换成其它符号,一般使用 / 或 #,当匹配字符串中也有 / 时,使用 # 比较方便。例如:

# sed 's#/sbin/nologin#cfop#g' /etc/passwd

这儿的意思是将 passwd 文件中所有的 /sbin/nologin 替换成 cfop,使用 # 就避免了对字符串中的 / 进行转义。

gpw 的解释:
g 缺省只替换每行的第一次出现模式,使用 g 替换所有模式。
p 仅将所有被替换行输出到标准输出。对于 s 命令,只有 -n 选项是不行的。
w 仅将所有被替换行输出重定向到文件(直接加 w 后面跟上文件名即可,用空格隔开)

使用s命令时包含变量的注意事项:

# cat test.txt
a b a

# x=a;y=b

# sed 's/$x/$y/g' test.txt            <-- 使用单引号时,变量不做替换
a b a

# sed ''s/$x/$y/g'' test.txt        <-- 将单引号改成双引号(或者不要引号)就可以了
b b b

# eval sed 's/$x/$y/g' test.txt        <-- 也可以使用eval命令把单引号里的变量进行计算
b b b

使用 & 保存发现模式:

使用 & 可以保存发现模式,这样就可以再次调用它,特别适用于发现模式使用了正则表达式的时候。

# cat demo.txt 
The local nurse Miss P.Neave was in attendance.

# sed -n 's/nurse/iamrhce &/p' demo.txt        <-- & 就是前面匹配模式的正则内容
The local iamrhce nurse Miss P.Neave was in attendance.

sed 命令之 s 后向引用

sed -nr ‘s#()()#\1\2#gp’ file

当在前面匹配部分用小括号的时候,第1个括号内容,可以在后面部分用1输出。第2个括号内容,可以在后面部分用2输出。

例1:把 'I am RHCA xuwang' 中的RHCA取出来

# echo 'I am RHCA xuwang' | sed -nr 's#^.*m (.*) x.*$#\1#gp'

例2:取出 oracle trace 目录的路径

通过 sql 语句查询到 trace 文件所在的目录,spool 到一个文件中,下面抓取其路径:

$ grep trace /tmp/check_trace.txt
/data/app/oracle/diag/rdbms/crdb/CYDB1/trace


我们看到 trace 目录后面有很多空白,这是因为 $ 结束符在后面的原因。
如果想取出文件中的路径,可以使用 awk 打印 $1,也可以使用下面的命令:

# sed -nr 's#(^.*trace).*$#\1#gp' /tmp/check_trace.txt

例3:取出 DB2 配置文件中的 key-value

有文件out.txt,内容如下,希望将等号左边第1个括号和等号右边的内容取出来:

Database Manager Configuration
     Node type = Enterprise Server Edition with local and remote clients
 Database manager configuration release level    = 0x1000
 CPU speed (millisec/instruction)     CPUSPEED) = 2.086187e-07
 Communications bandwidth (MB/sec)    (COMM_BANDWIDTH) = 1.000000e+02
 Max number of concurrently active databases    (NUMDB) = 32 
 Current effective arch level   (CUR_EFF_ARCH_LVL) = V:10 R:5 M:0 F:3 I:0 SB:0

解法:

$ sed -nr 's#^.*(\(.*\) =.*$)#\1#gp' out.txt 
(CPUSPEED) = 2.086187e-07
(COMM_BANDWIDTH) = 1.000000e+02
(NUMDB) = 32
(CUR_EFF_ARCH_LVL) = V:10 R:5 M:0 F:3 I:0 SB:0

例4:将 passwd 文件中的第1列与最后一列互换

# sed -nr 's#([^:]+)(:.*:)(/.*$)#\3\2\1#gp' /etc/passwd

([^:]+)表示不是冒号重复1次或多次,即用户名,(:.*:)表示中间的部分,(/.*$)表示最后一列。

同时执行多个 sed 命令

如果想在一条 sed shell 命令中同时执行多个 sed 命令,可以使用 -e 选项来指定每个命令。

例如,可以使用 -e 将多个 s 命令拼接起来,同时完成多个替换:

sed -e 's/Installing/install/g' -e 's/i686/x86_64/g'  install.log

可以使用 -e 将多个不同的 sed 命令拼接起来:

# sed -n -e  '5s#/sbin/nologin#cfop#gp' -e '5a Goodluck' /etc/passwd

sed 的模式空间和保持空间

这是一个高级话题,我们另开一章,见文。

-- By 许望(RHCA、OCM、VCP)
最后修改:2020 年 01 月 02 日 08 : 33 PM
如果觉得我的文章对你有用,请随意赞赏