sed命令
sed 命令详解:流编辑器的文本处理艺术
sed(Stream Editor,流编辑器)是 Linux 中处理文本的核心工具之一,它以逐行处理的方式对数据流进行编辑(如替换、删除、新增等),且默认不修改原文件,仅输出处理结果。掌握 sed 能高效完成批量文本修改、日志分析、配置文件处理等任务。
sed 工作原理与基本语法
工作流程
- 读取:从输入流(文件或管道)中读取一行数据到缓冲区(称为 “模式空间”)。
- 处理:根据提供的
sed命令(规则)处理缓冲区中的行。 - 输出:将处理后的行输出到标准输出(屏幕)。
- 重复:直到所有行处理完毕。
特点:默认不修改原文件,仅输出处理结果;可通过 -i 选项直接修改原文件。
基本语法
sed [选项] '地址范围 动作' 输入文件
核心选项
| 选项 | 功能说明 |
|---|---|
-n |
静默模式,仅输出被 p 动作指定的行(抑制默认输出)。 |
-e |
允许在同一行指定多个 sed 命令(多命令执行)。 |
-f 脚本文件 |
从文件中读取 sed 命令(适合复杂脚本)。 |
-r |
启用扩展正则表达式(无需转义 +、? 等元字符)。 |
-i |
直接修改原文件(危险操作,建议先备份或测试)。 |
常用动作
| 动作 | 功能说明 |
|---|---|
a \文本 |
在指定行后追加文本(多行需用 \ 分隔)。 |
i \文本 |
在指定行前插入文本(多行需用 \ 分隔)。 |
c \文本 |
用指定文本替换整行(多行需用 \ 分隔)。 |
d |
删除指定行。 |
p |
打印指定行(常与 -n 配合使用)。 |
s/旧字符串/新字符串/修饰符 |
替换字符(核心动作,详见下文)。 |
w 文件名 |
将指定行写入文件。 |
地址范围:指定要处理的行
sed 通过 “地址范围” 指定对哪些行执行动作,默认对所有行生效。地址可以是行号、正则表达式或两者结合。
行号寻址
- 单一行:
数字(如3表示第 3 行)。 - 行范围:
起始行,结束行(如2,5表示第 2 到 5 行)。 - 从行号到结尾:
数字,$( 表示第 3 行到最后一行)。
示例:
# 打印第2行(-n 配合 p 仅输出指定行)
sed -n '2p' file.txt
# 删除第3到5行
sed '3,5d' file.txt
# 从第4行到结尾,每行后追加"---"
sed '4,$a ---' file.txt
正则表达式寻址
用 /正则表达式/ 匹配行,仅处理符合条件的行。
- 格式:
/pattern/动作(如/error/d表示删除包含error的行)。 - 扩展正则需加
-r选项(如/^[0-9]+/p匹配以数字开头的行)。
示例:
# 打印包含 "error" 的行(日志分析常用)
sed -n '/error/p' app.log
# 删除以 "#" 开头的注释行(不包括空行)
sed '/^#/d' config.ini
# 替换以 "name:" 开头的行中的 "old" 为 "new"
sed -r '/^name:/s/old/new/' data.txt
混合寻址
结合行号和正则,实现更精确的范围选择。
# 从第5行开始,到包含 "end" 的行结束,删除这些行
sed '5,/end/d' file.txt
# 从包含 "start" 的行到第10行,每行前插入 "==="
sed '/start/,10i ===' file.txt
核心动作详解:替换、删除、新增
字符替换(s 动作)
sed 最常用的功能,格式:s/旧字符串/新字符串/修饰符。
修饰符
g:全局替换(默认仅替换每行第一个匹配项)。n:替换第n个匹配项(如s/old/new/2替换每行第二个old)。p:替换后打印该行(常与-n配合,输出被修改的行)。i:忽略大小写(如s/hello/HELLO/i不区分大小写替换)。
示例:
# 将每行第一个 "apple" 替换为 "banana"
sed 's/apple/banana/' fruit.txt
# 全局替换所有 "cat" 为 "dog"
sed 's/cat/dog/g' pets.txt
# 替换第2个 "error" 为 "warning",并打印修改的行
sed -n 's/error/warning/2p' app.log
# 忽略大小写替换 "hello" 为 "HELLO"
sed 's/hello/HELLO/i' greet.txt
删除行(d 动作)
用于删除指定行,注意 d 后无其他内容。
# 删除空行(正则 ^$ 匹配空行)
sed '/^$/d' file.txt
# 删除所有包含 "temp" 的行
sed '/temp/d' list.txt
# 保留第2到5行,删除其他行(反向思维:先删除所有行,再恢复指定行)
sed '1d;6,$d' file.txt # 分号分隔多个命令
新增与替换行(a/i/c 动作)
a:在指定行后追加;i:在指定行前插入;c:替换整行。
示例:
# 在第3行后追加 "new line"
sed '3a new line' file.txt
# 在包含 "title" 的行前插入两行文本(多行用 \ 分隔)
sed '/title/i line1\nline2' file.txt # 或用 \ 换行:i line1\ line2
# 用 "replaced" 替换所有以 "old" 开头的行
sed '/^old/c replaced' file.txt
写入文件(w 动作)
将指定行写入其他文件(可用于提取特定内容)。
# 将第1到5行写入 output.txt
sed '1,5w output.txt' input.txt
# 将包含 "success" 的行写入 success.log
sed -n '/success/w success.log' app.log # -n 避免重复输出
高级用法:多命令、原地修改与脚本
多命令执行
- 用
-e选项分隔多个命令,或用分号;连接。
# 同时删除空行和注释行(# 开头)
sed -e '/^$/d' -e '/^#/d' config.ini
# 等价写法(分号连接)
sed '/^$/d;/^#/d' config.ini
原地修改文件(-i 选项)
-i 选项让 sed 直接修改原文件(务必谨慎使用,建议先备份)。
# 备份原文件(加 .bak 后缀),再修改
sed -i.bak 's/old/new/g' file.txt # 修改后生成 file.txt.bak
# 直接修改原文件(无备份,危险!)
sed -i 's/error/warn/g' app.log
从脚本文件读取命令(-f 选项)
复杂的 sed 操作可写入脚本文件,提高可读性。
# 脚本文件:sed_commands.sed
s/hello/hi/g
/^test/d
3a --- END ---
# 执行脚本
sed -f sed_commands.sed input.txt
实战案例
1. 批量修改文件名
# 将当前目录下所有 .txt 文件名中的 "old" 改为 "new"
ls *.txt | sed -n 's/old/new/p' | xargs -I {} mv {old} {new}
# 解析:sed 生成新文件名,xargs 执行 mv 命令
2. 清理 Nginx 日志(保留关键信息)
# 提取日志中的 IP、时间、请求路径(假设日志格式:IP 时间 "请求" ...)
sed -r 's/^([0-9.]+) .* \[(.*)\] ".* (\/.*?) .*/\1 \2 \3/' access.log
# 解析:用正则分组提取 IP(\1)、时间(\2)、路径(\3)
3. 配置文件批量替换
# 将所有 .conf 文件中的 "port 80" 改为 "port 8080",并备份
find . -name "*.conf" -exec sed -i.bak 's/port 80/port 8080/g' {} \;
注意事项
- 正则转义:基础
sed中某些元字符(如+、?)需用\转义,加-r选项可避免。 - 特殊字符处理:替换包含
/的字符串时,可改用其他分隔符(如s#/old#/new#g)。 - 原文件保护:使用
-i前建议先备份(如-i.bak),或先不加-i测试输出是否正确。 - 空行与空格:正则
^$匹配空行,^[[:space:]]*$匹配空行或仅含空格的行。