sed(Stream EDitor,流编辑器)是 Unix/Linux 系统中的一个强大工具,用于处理和转换文本流。它是非交互式的,可以从标准输入、文件或管道中读取数据,进行编辑(如替换、删除、插入),并将结果输出到标准输出,而不修改原文件(除非指定重定向)。sed 基于正则表达式工作,特别适合批量处理脚本或自动化任务。它源于 ed 编辑器,但专注于一行一行的处理。
sed 的设计哲学是"一次处理一行",这使得它高效且适合大文件。相比 awk,sed 更侧重于简单编辑;相比 grep,它支持修改而非仅搜索。
基本语法
sed 的基本语法如下:
sed [选项] '命令' [输入文件]
- 如果没有指定输入文件,sed 会从标准输入读取。
- 输出默认到标准输出,可以用 > 重定向到文件。
- 命令通常用单引号包围,以避免 shell 解释特殊字符。
示例:
- 从文件读取并处理:sed 's/old/new/' file.txt
- 通过管道:cat file.txt | sed 's/old/new/'
常用选项
sed 支持多种选项来控制行为。以下是常见选项的表格:
| 选项 | 描述 | 示例 |
|---|---|---|
| -n | 抑制自动打印模式空间(只打印显式指定的行)。 | sed -n 'p' file.txt(相当于 cat,但只打印匹配行) |
| -e | 指定多个命令(默认可省略,如果只有一个命令)。 | sed -e 's/a/b/' -e 's/c/d/' file.txt |
| -f | 从文件中读取 sed 脚本。 | sed -f script.sed file.txt |
| -i | 原地编辑文件(直接修改原文件)。添加后缀如 -i.bak 可备份。 | sed -i 's/old/new/' file.txt |
| -r 或 -E | 使用扩展正则表达式(支持 ?、+、{} 等无需转义)。 | `sed -r 's/(a |
| -s | 将多个文件视为单独文件处理(默认视为一个流)。 | sed -s 's/old/new/' file1.txt file2.txt |
地址定位
sed 可以指定处理的行范围(地址),否则处理所有行。地址可以是数字、正则或组合。
- 数字地址:如 2(第2行)、2,5(第2到5行)、2,+3(第2行及其后3行)、$(最后一行)。
- 正则地址:用 /regex/ 包围,如 /pattern/(匹配 pattern 的行)。
- 步进:如 1~2(从第1行开始,每隔2行)。
- 否定:加 ! 如 2!d(删除除第2行外的所有行)。
示例:
- 处理第3到最后一行:sed '3,$ s/old/new/' file.txt
- 处理包含 "error" 的行:sed '/error/d' file.txt
常用命令
sed 的命令是核心,通常是单字母操作,可能带参数。多个命令用分号 ; 分隔,或用 -e。
以下是常见命令的表格,按类别分类:
| 类别 | 命令 | 描述 | 示例 |
|---|---|---|---|
| 替换 | s/regex/replacement/[flags] | 替换匹配的正则为新文本。flags: g(全局)、p(打印)、i(忽略大小写)、数字(第n次匹配)。 | sed 's/foo/bar/g' file.txt(全局替换 foo 为 bar) |
| 删除 | d | 删除匹配行。 | sed '/^#/d' file.txt(删除以 # 开头的注释行) |
| 打印 | p | 打印匹配行(常与 -n 结合)。 | sed -n '/pattern/p' file.txt(只打印匹配行) |
| 插入/追加 | i\text 或 a\text | 在匹配行前(i)或后(a)插入文本。 | sed '/start/i\new line' file.txt |
| 更改 | c\text | 用新文本替换整行。 | sed '/old/c\new content' file.txt |
| 读取/写入文件 | r file 或 w file | 读取外部文件插入,或写入匹配到文件。 | sed '/end/r footer.txt' file.txt(在 end 后插入 footer.txt 内容) |
| 转换 | y/src/dest/ | 字符转换(如 tr 命令)。 | sed 'y/abc/123/' file.txt(a->1, b->2, c->3) |
| 分支/标签 | :label、b label、t label | 条件跳转,用于复杂逻辑。 | sed ':a; N; $!ba; s/\n/ /g' file.txt(将多行合并为一行) |
| 分组 | { commands } | 对地址应用多个命令。 | sed '/pattern/{s/a/b/; d}' file.txt |
| 其他 | =(打印行号)、q(退出)、N(读取下一行到模式空间)、D(删除多行模式空间首行) | 用于行号、提前退出、多行处理。 | sed -n '/pattern/=' file.txt(打印匹配行的行号) |
正则表达式支持
sed 默认使用基本正则(BRE),用 -r 切换到扩展正则(ERE)。常见元字符:
- .(任意字符)、*(0或多)、^(行首)、$(行尾)、[](字符类)、\( \)(分组,反向引用如 \1)。
- 在 ERE 中:+(1或多)、?(0或1)、(或)、{n,m}(重复)无需转义。
示例:sed -r 's/[0-9]{3}-[0-9]{3}-[0-9]{4}/XXX-XXX-XXXX/' file.txt(掩码电话号码)。
高级用法:持空间与模式空间
- 模式空间(Pattern Space):当前处理的行(或多行用 N 合并)。
- 持空间(Hold Space) :临时存储区,用于交换数据。
-
h 或 H:复制/追加模式到持空间。
-
g 或 G:复制/追加持空间到模式。
-
x:交换两者。 示例:反转文件行序(复杂脚本):
sed '1!G; h; $!d' file.txt
-
常见示例
- 替换文本:sed 's/Apple/Orange/g' fruits.txt > new_fruits.txt
- 删除空行:sed '/^$/d' file.txt
- 添加行号:sed = file.txt | sed 'N; s/\n/\t/'
- 处理 CSV:sed 's/","/ /g' data.csv(逗号替换为空格)。
- 多行替换:sed '/start/,/end/d' file.txt(删除 start 到 end 间的块)。
- 备份并修改:sed -i.bak 's/error/warning/' log.txt
- 与 find 结合:find . -type f -exec sed -i 's/old/new/g' {} +(批量替换目录下文件)。
注意事项与最佳实践
- sed 不修改原文件,除非用 -i。总是测试后使用。
- 对于复杂正则,转义特殊字符如 / 用 \/。
- 与 grep/awk 结合:grep 搜索、sed 编辑、awk 结构化处理。
- 调试:用 -n 和 p 查看中间结果。
- 性能:sed 高效于大文件,但脚本复杂时考虑 Perl 或 Python。
- 移植性:GNU sed(Linux 默认)有扩展;BSD sed 略不同。