linux 提供了强大的文本分析工具,如 grep, sed, awk,号称三剑客。本篇介绍文本编辑命令 sed

sedstream editor,流编辑器)命令能够通过模式匹配(如正则表达式)对指定的行进行编辑文本内容。默认在所有 linux 发行版中都预装该命令。

sed 处理文本以行为单位,处理时将当前行存储到临时缓冲区(称为模式空间 “pattern space”),然后 sed 对缓冲区的内容执行动作进行文本编辑,处理完成后将缓冲区的内容送往屏幕,接着处理下一行,直至文件末尾。默认不修改原文件内容,不过可以指定命令参数(如 -i)将修改后的内容重定向输出。

基本命令格式

1
2
3
sed [options] '[addr]command[flags]' filename
# or
sed [options] "[addr]command[flags]" filename

示例:

1
2
3
4
5
6
# -e 是 options,表示直接在命令行上进行编辑,默认选项,不指定其他选项默认就是该选项
# 1 是 addr,表示在 hello.py 文件的第一行操作
# s 是 command 命令动作,表示替换,/xxx/yyy/ 表示将文件内容 xxx 替换为 yyy
# g 是 flags 表示全部、全局,这里表示对第 1 行的所有 xxx 都替换为 yyy
# hello.py 是 filename,表示被操作的文件
sed -e '1s/xxx/yyy/g' hello.py

options

options 是 sed 命令作用于整个文档的全局范围,注意与 flags 的区别,flags 针对 addr 作用在具体的行上,执行 command 动作。

options 含义
-e 直接在命令行上进行文本编辑,默认选项
-f sed-filenme 从 sed-filename 中读取 sed 动作,如果动作过多,那么可以写入文件内,-f 直接从文件中读取动作
-i 直接修改文件内容。即 sed 将编辑后的文本内容重定向覆盖存储到原文件
-n 只打印模式匹配到的行。如果不指定,会把文件所有内容打印到屏幕
-r 支持扩展正则表达式

addr

addr 就是行号,不指定时表示所有行,即整个文档。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
# 指定所有行。缺省时表示匹配整个文档所有行
sed -n 's/xxx/yyy/p' hello.py

# 指定第 1 行,对该行中的 xxx 全部(g)替换为 yyy
sed -n '1s/xxx/yyy/gp' hello.py

# 指定第 2 到 5 行,并只替换第 2 到 5 行中的第一个(1)匹配到的 xxx 替换为 yyy
sed -n '2,5s@xxx@yyy@1p' hello.py

# 缺省 flags 值 g 时,默认为匹配该行的第一个
sed -n '2,5s@xxx@yyy@p' hello.py

# 指定第 3 到最后一行,并对每行替换第二个匹配到的 xxx 为 yyy
sed -n "3,$s#xxx#yyy#2gp" hello.py

# 上面的 /, @, # 为定界符,也可以用 :, | 等

flags

flags 表示针对指定的行执行动作,如全局替换、只替换 1 个、删除、打印等。

flags 含义
g 表示行内全面替换: sed -i "1,3s/xxx/yyy/g" hello.py
p 表示打印行,默认会打印所有文档内容。常和 -n 参数一起使用,表示只打印匹配的行:sed -n "1,$s/xxx/p" hello.py
d 表示删除匹配的内容:sed '4,$/^#/d' hello.py 表示从第 4 行到文档结尾删除以 # 开头的行
i 表示在匹配的内容前添加,类似于 vim 的 i:sed '3i there are insert words' hello.py 表示在第 3 行前增加一行内容 “there are insert words”
a 表示在匹配的内容后添加,类似于 vim 的 a:sed '3a there are insert words\ there are another insert line' hello.py 表示在第 3 行后增加两行内容
c 表示替换某行内容:sed '3c This is changed line' hello.py,表示替换第 3 行内容为:”This is changed line”. 匹配替换:sed '/xjz/c author is jinzhongxu' hello.py 表示把 hello.py 中包含 xjz 的行替换为 jinzhongxu
y 表示转换,如 sed 'y/123/456/' hello.py 表示把 hello.py 中的 1 转写为 4, 2 转写为 5, 3 转写为 6
w 表示把匹配的行写入到新文件中,新文件不存在时会自动创建:sed '1w hello.txt' hello.py 把 hello.py 的第一行写入到 hello.txt 中;sed -n '/mail/w hello.txt' hello.py 把 hello.py 中包含 mail 的行覆盖写入到 hello.txt
r 把其他文件的内容插入到文件指定的行:sed '3r hello.txt' hello.py 把 hello.txt 的内容插入到 hello.py 的第 3 行后;sed '1~1r a.txt' test.txt 在每一行的后面插入 a.txt; sed '1~2r a.txt' test.txt 在奇数行的后面插入 a.txt; sed '/z/r a.txt' test.txt 在匹配 z 的行后面插入 a.txt
q 退出脚本:sed '2q' hello.py 只打印 hello.py 的第 2 行,然后退出; sed '/root/{s/bash/zsh/;q}' /etc/passwd 把匹配到 root 的第一个匹配的行的 bash 替换为 zsh,然后退出

示例:

1
2
3
4
5
6
7
8
# 多个命令用大括号
# 把包含 root 字符串的行先打印,然后替换 bash 为 zsh 再打印
sed -n -e '/root/{p
> s/bash/zsh/p
> }' pwd.txt

# or
sed -n '/root/{p;s/bash/zsh/p}' pwd.txt

参考文献

  1. Linux sed 命令
  2. Linux之sed命令
  3. sed
  4. Linux文本处理三剑客:Grep/Sed/Awk详解